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.
8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 |
# File 'lib/idlc/ast.rb', line 8315 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.
8335 8336 8337 |
# File 'lib/idlc/ast.rb', line 8335 def argument_nodes @argument_nodes end |
#return_type_nodes ⇒ Object (readonly)
Returns the value of attribute return_type_nodes.
8291 8292 8293 |
# File 'lib/idlc/ast.rb', line 8291 def return_type_nodes @return_type_nodes end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 |
# File 'lib/idlc/ast.rb', line 8585 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
8297 8298 8299 8300 8301 |
# File 'lib/idlc/ast.rb', line 8297 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
8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 |
# File 'lib/idlc/ast.rb', line 8479 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
8455 8456 8457 8458 8459 |
# File 'lib/idlc/ast.rb', line 8455 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.
8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 |
# File 'lib/idlc/ast.rb', line 8348 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
8371 8372 8373 |
# File 'lib/idlc/ast.rb', line 8371 def arguments_list_str @argument_nodes.map(&:text_value) end |
#body ⇒ Object
8507 8508 8509 8510 8511 |
# File 'lib/idlc/ast.rb', line 8507 def body internal_error "Function has no body" if builtin? || generated? @body end |
#builtin? ⇒ Boolean
8513 8514 8515 |
# File 'lib/idlc/ast.rb', line 8513 def builtin? @builtin end |
#const_eval?(symtab) ⇒ Boolean
8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 |
# File 'lib/idlc/ast.rb', line 8427 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.
8338 8339 8340 |
# File 'lib/idlc/ast.rb', line 8338 def description unindent(@desc) end |
#eql?(other) ⇒ Boolean
8303 8304 8305 |
# File 'lib/idlc/ast.rb', line 8303 def eql?(other) name.eql?(other.name) end |
#external? ⇒ Boolean
8521 8522 8523 |
# File 'lib/idlc/ast.rb', line 8521 def external? @external end |
#generated? ⇒ Boolean
8517 8518 8519 |
# File 'lib/idlc/ast.rb', line 8517 def generated? @generated end |
#name ⇒ Object
8451 8452 8453 |
# File 'lib/idlc/ast.rb', line 8451 def name @name end |
#num_args ⇒ Integer
Returns The number of arguments to the function.
8343 8344 8345 |
# File 'lib/idlc/ast.rb', line 8343 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
8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 |
# File 'lib/idlc/ast.rb', line 8525 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
8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 |
# File 'lib/idlc/ast.rb', line 8376 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
8415 8416 8417 8418 8419 8420 8421 |
# File 'lib/idlc/ast.rb', line 8415 def return_type_list_str if @return_type_nodes.empty? ["void"] else @return_type_nodes.map(&:text_value) end end |
#to_h ⇒ Object
8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 |
# File 'lib/idlc/ast.rb', line 8573 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
8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 |
# File 'lib/idlc/ast.rb', line 8538 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
8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 |
# File 'lib/idlc/ast.rb', line 8462 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
8497 8498 8499 |
# File 'lib/idlc/ast.rb', line 8497 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
8501 8502 8503 8504 8505 |
# File 'lib/idlc/ast.rb', line 8501 def type_check_body(symtab, strict:) return if @body.nil? @body.type_check(symtab, strict:) end |
#type_check_return(symtab, strict:) ⇒ Object
8493 8494 8495 |
# File 'lib/idlc/ast.rb', line 8493 def type_check_return(symtab, strict:) @return_type_nodes.each { |r| r.type_check(symtab, strict:) } end |