Class: Idl::FunctionDefAst
- Includes:
- Declaration
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb
Defined Under Namespace
Classes: Memo
Constant Summary
Constants inherited from AstNode
AstNode::Bits1Type, AstNode::Bits32Type, AstNode::Bits64Type, AstNode::BoolType, AstNode::ConstBoolType, AstNode::PossiblyUnknownBits1Type, AstNode::PossiblyUnknownBits32Type, AstNode::PossiblyUnknownBits64Type, AstNode::ReachableFunctionCacheType, AstNode::StringType, AstNode::VoidType
Instance Attribute Summary collapse
-
#argument_nodes ⇒ Object
readonly
Returns the value of attribute argument_nodes.
-
#return_type_nodes ⇒ Object
readonly
Returns the value of attribute return_type_nodes.
Attributes inherited from AstNode
#children, #input, #interval, #parent
Class Method Summary collapse
Instance Method Summary collapse
- #<=>(other) ⇒ Object
-
#add_symbol(symtab) ⇒ Object
Add symbol(s) at the outermost scope of the symbol table.
- #apply_arg_syms(symtab) ⇒ Object
-
#arguments(symtab) ⇒ Array<Array(Type,String)>
Containing the argument types and names, in order.
-
#arguments_list_str ⇒ Object
returns an array of arguments, as a string function does not need to be resolved.
- #body ⇒ Object
- #builtin? ⇒ Boolean
- #const_eval?(symtab) ⇒ Boolean
-
#description ⇒ String
Asciidoc formatted function description.
- #eql?(other) ⇒ Boolean
- #external? ⇒ Boolean
- #generated? ⇒ Boolean
-
#initialize(input, interval, name, return_types, arguments, desc, type, body) ⇒ FunctionDefAst
constructor
A new instance of FunctionDefAst.
- #name ⇒ Object
-
#num_args ⇒ Integer
The number of arguments to the function.
- #prune(symtab, forced_type: nil) ⇒ Object
- #qualifier_str ⇒ Object
-
#return_type(symtab) ⇒ Object
return the return type, which may be a tuple of multiple types.
-
#return_type_list_str ⇒ Array<String>
function does not need to be resolved.
- #to_h ⇒ Object
- #to_idl ⇒ Object
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
- #type_check_args(symtab, strict:) ⇒ Object
- #type_check_body(symtab, strict:) ⇒ Object
- #type_check_return(symtab, strict:) ⇒ Object
Methods included from Declaration
Methods inherited from AstNode
#always_terminates?, #declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_dst_registers, #find_referenced_csrs, #find_src_registers, #freeze_tree, #gen_adoc, #gen_option_adoc, #input_file, input_from_source_yaml, #inspect, #internal_error, interval_from_source_yaml, #lineno, #lines_around, #nullify_assignments, #pass_find_return_values, #path, #print_ast, #reachable_exceptions, #reachable_functions, #set_input_file, #set_input_file_unless_already_set, #source_line_file_offsets, #source_starting_offset, #source_yaml, #starting_line, #text_value, #truncation_warn, #type_error, #unindent, value_else, #value_else, value_error, #value_error, value_try, #value_try, write_back_nested
Constructor Details
#initialize(input, interval, name, return_types, arguments, desc, type, body) ⇒ FunctionDefAst
Returns a new instance of FunctionDefAst.
8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 |
# File 'lib/idlc/ast.rb', line 8300 def initialize(input, interval, name, return_types, arguments, desc, type, body) if body.nil? super(input, interval, return_types + arguments) else super(input, interval, return_types + arguments + [body]) end @name = name @return_type_nodes = return_types @argument_nodes = arguments @desc = desc @body = body @builtin = type == :builtin @generated = type == :generated @external = type == :external @cached_return_type = {} @memo = Memo.new end |
Instance Attribute Details
#argument_nodes ⇒ Object (readonly)
Returns the value of attribute argument_nodes.
8320 8321 8322 |
# File 'lib/idlc/ast.rb', line 8320 def argument_nodes @argument_nodes end |
#return_type_nodes ⇒ Object (readonly)
Returns the value of attribute return_type_nodes.
8276 8277 8278 |
# File 'lib/idlc/ast.rb', line 8276 def return_type_nodes @return_type_nodes end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 |
# File 'lib/idlc/ast.rb', line 8570 def self.from_h(yaml, source_mapper) raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "function_decl" input = input_from_source_yaml(yaml.fetch("source"), source_mapper) interval = interval_from_source_yaml(yaml.fetch("source")) FunctionDefAst.new( input, interval, yaml.fetch("name"), yaml.fetch("return_types").map { |r| AstNode.from_h(r, source_mapper) }, yaml.fetch("arguments").map { |a| AstNode.from_h(a, source_mapper) }, yaml.fetch("description"), yaml.fetch("qualifier").to_sym, yaml.fetch("body").nil? ? nil : AstNode.from_h(yaml.fetch("body"), source_mapper) ) end |
Instance Method Details
#<=>(other) ⇒ Object
8282 8283 8284 8285 8286 |
# File 'lib/idlc/ast.rb', line 8282 def <=>(other) return nil unless other.is_a?(FunctionDefAst) @name <=> other.name end |
#add_symbol(symtab) ⇒ Object
Add symbol(s) at the outermost scope of the symbol table
8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 |
# File 'lib/idlc/ast.rb', line 8464 def add_symbol(symtab) internal_error "Functions should be declared at global scope" unless symtab.levels == 1 type_error "Cannot use reserved word '#{name}' as function name" if ReservedWords::RESERVED.include?(name) # now add the function in global scope def_type = FunctionType.new( name, self, symtab ) symtab.add!(name, def_type) end |
#apply_arg_syms(symtab) ⇒ Object
8440 8441 8442 8443 8444 |
# File 'lib/idlc/ast.rb', line 8440 def apply_arg_syms(symtab) arguments(symtab).each do |arg_type, arg_name| symtab.add(arg_name, Var.new(arg_name, arg_type)) end end |
#arguments(symtab) ⇒ Array<Array(Type,String)>
Returns containing the argument types and names, in order.
8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 |
# File 'lib/idlc/ast.rb', line 8333 def arguments(symtab) return @memo.arguments unless @memo.arguments.nil? return EMPTY_ARRAY if @argument_nodes.empty? arglist = [] @argument_nodes.each do |a| atype = a.type(symtab) type_error "No type for #{a.text_value}" if atype.nil? atype = atype.ref_type if atype.kind == :enum atype = atype.make_const if a.id.text_value[0].upcase == a.id.text_value[0] arglist << [atype, a.name] end arglist.freeze @memo.arguments = arglist end |
#arguments_list_str ⇒ Object
returns an array of arguments, as a string function does not need to be resolved
8356 8357 8358 |
# File 'lib/idlc/ast.rb', line 8356 def arguments_list_str @argument_nodes.map(&:text_value) end |
#body ⇒ Object
8492 8493 8494 8495 8496 |
# File 'lib/idlc/ast.rb', line 8492 def body internal_error "Function has no body" if builtin? || generated? @body end |
#builtin? ⇒ Boolean
8498 8499 8500 |
# File 'lib/idlc/ast.rb', line 8498 def builtin? @builtin end |
#const_eval?(symtab) ⇒ Boolean
8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 |
# File 'lib/idlc/ast.rb', line 8412 def const_eval?(symtab) return false if builtin? || generated? # set up dummy const args, and see if the type comes out is const symtab = symtab.global_clone symtab.push(self) arguments(symtab).each do |arg_type, arg_name| # make the argument constant for this evaluation arg_type = arg_type.make_const symtab.add(arg_name, Var.new(arg_name, arg_type)) end symtab.add( "__expected_return_type", return_type(symtab) ) is_const_eval = @body.const_eval?(symtab) symtab.release is_const_eval end |
#description ⇒ String
Returns Asciidoc formatted function description.
8323 8324 8325 |
# File 'lib/idlc/ast.rb', line 8323 def description unindent(@desc) end |
#eql?(other) ⇒ Boolean
8288 8289 8290 |
# File 'lib/idlc/ast.rb', line 8288 def eql?(other) name.eql?(other.name) end |
#external? ⇒ Boolean
8506 8507 8508 |
# File 'lib/idlc/ast.rb', line 8506 def external? @external end |
#generated? ⇒ Boolean
8502 8503 8504 |
# File 'lib/idlc/ast.rb', line 8502 def generated? @generated end |
#name ⇒ Object
8436 8437 8438 |
# File 'lib/idlc/ast.rb', line 8436 def name @name end |
#num_args ⇒ Integer
Returns The number of arguments to the function.
8328 8329 8330 |
# File 'lib/idlc/ast.rb', line 8328 def num_args @argument_nodes.size end |
#prune(symtab, forced_type: nil) ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/idlc/passes/prune.rb', line 283 def prune(symtab, forced_type: nil) pruned_body = unless builtin? || generated? apply_arg_syms(symtab) @body.prune(symtab, args_already_applied: true) end FunctionDefAst.new( input, interval, name, @return_type_nodes.map(&:dup), @argument_nodes.map(&:dup), @desc, @type, pruned_body ) end |
#qualifier_str ⇒ Object
8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 |
# File 'lib/idlc/ast.rb', line 8510 def qualifier_str if external? "external" elsif builtin? "builtin" elsif generated? "generated" else "" end end |
#return_type(symtab) ⇒ Object
return the return type, which may be a tuple of multiple types
8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 |
# File 'lib/idlc/ast.rb', line 8361 def return_type(symtab) cache_key = "#{symtab.name}/#{symtab.mxlen}" cached = @cached_return_type[cache_key] # only cached for non-template functions return cached unless cached.nil? unless symtab.levels == 2 internal_error "Function bodies should be at global + 1 scope (at global + #{symtab.levels - 1})" end if @return_type_nodes.empty? @cached_return_type[cache_key] = VoidType return VoidType end rtype = T.let(nil, T.nilable(Type)) rtype = if @return_type_nodes.size == 1 rtype = @return_type_nodes[0].type(symtab) rtype = rtype.ref_type if rtype.kind == :enum rtype else tuple_types = @return_type_nodes.map do |r| rtype = r.type(symtab) rtype = rtype.ref_type if rtype.kind == :enum rtype end Type.new(:tuple, tuple_types:) end raise "??????" if rtype.nil? return @cached_return_type[symtab.name] = rtype end |
#return_type_list_str ⇒ Array<String>
function does not need to be resolved
8400 8401 8402 8403 8404 8405 8406 |
# File 'lib/idlc/ast.rb', line 8400 def return_type_list_str if @return_type_nodes.empty? ["void"] else @return_type_nodes.map(&:text_value) end end |
#to_h ⇒ Object
8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 |
# File 'lib/idlc/ast.rb', line 8558 def to_h = { "kind" => "function_decl", "name" => name, "qualifier" => qualifier_str.empty? ? "normal" : qualifier_str, "return_types" => return_type_nodes.map(&:to_h), "arguments" => @argument_nodes.map(&:to_h), "description" => @desc, "body" => @body&.to_h, "source" => source_yaml } |
#to_idl ⇒ Object
8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 |
# File 'lib/idlc/ast.rb', line 8523 def to_idl qualifier = qualifier_str returns_idl = if return_type_nodes.empty? "" else "returns #{return_type_nodes.map(&:to_idl).join(', ')}" end args_idl = if @argument_nodes.empty? "" else "arguments #{@argument_nodes.map(&:to_idl).join(", ")}" end body_idl = if builtin? || generated? "" else "body { #{@body.to_idl} }" end <<~IDL #{qualifier} function #{name} { #{returns_idl} #{args_idl} description { #{description} } #{body_idl} } IDL end |
#type_check(symtab, strict:) ⇒ void
This method returns an undefined value.
type check this node and all children
Calls to #type and/or #value may depend on type_check being called first with the same symtab. If not, those functions may raise an AstNode::InternalError
8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 |
# File 'lib/idlc/ast.rb', line 8447 def type_check(symtab, strict:) internal_error "Functions must be declared at global scope (at #{symtab.levels})" unless symtab.levels == 1 symtab = symtab.deep_clone symtab.push(self) type_check_return(symtab, strict:) apply_arg_syms(symtab) type_check_args(symtab, strict:) type_check_body(symtab, strict:) symtab.pop end |
#type_check_args(symtab, strict:) ⇒ Object
8482 8483 8484 |
# File 'lib/idlc/ast.rb', line 8482 def type_check_args(symtab, strict:) @argument_nodes.each { |a| a.type_check(symtab, add_sym: false, strict:, is_function_arg: true) } end |
#type_check_body(symtab, strict:) ⇒ Object
8486 8487 8488 8489 8490 |
# File 'lib/idlc/ast.rb', line 8486 def type_check_body(symtab, strict:) return if @body.nil? @body.type_check(symtab, strict:) end |
#type_check_return(symtab, strict:) ⇒ Object
8478 8479 8480 |
# File 'lib/idlc/ast.rb', line 8478 def type_check_return(symtab, strict:) @return_type_nodes.each { |r| r.type_check(symtab, strict:) } end |