Class: Idl::AstNode
- Inherits:
-
Object
- Object
- Idl::AstNode
- Extended by:
- T::Helpers, T::Sig
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/type.rb,
lib/idlc/ast_decl.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/gen_option_adoc.rb,
lib/idlc/passes/find_return_values.rb,
lib/idlc/passes/find_src_registers.rb,
lib/idlc/passes/reachable_functions.rb,
lib/idlc/passes/find_referenced_csrs.rb,
lib/idlc/passes/reachable_exceptions.rb
Overview
set up a default
Direct Known Subclasses
ArrayIncludesAst, ArrayLiteralAst, ArraySizeAst, AryElementAccessAst, AryElementAssignmentAst, AryRangeAccessAst, AryRangeAssignmentAst, BinaryExpressionAst, BitfieldDefinitionAst, BitfieldFieldDefinitionAst, BitsCastAst, BuiltinEnumDefinitionAst, BuiltinTypeNameAst, BuiltinVariableAst, CommentAst, ConcatenationExpressionAst, ConditionalReturnStatementAst, ConditionalStatementAst, ConstraintBodyAst, CsrFieldAssignmentAst, CsrFieldReadExpressionAst, CsrFunctionCallAst, CsrReadExpressionAst, CsrSoftwareWriteAst, CsrWriteAst, DontCareLvalueAst, DontCareReturnAst, ElseIfAst, EnumArrayCastAst, EnumCastAst, EnumDefinitionAst, EnumElementSizeAst, EnumRefAst, EnumSizeAst, FalseExpressionAst, FetchAst, FieldAccessExpressionAst, FieldAssignmentAst, ForLoopAst, FunctionBodyAst, FunctionCallExpressionAst, FunctionDefAst, GlobalAst, GlobalWithInitializationAst, IdAst, IfAst, IfBodyAst, ImplicationExpressionAst, ImplicationStatementAst, IncludeStatementAst, IntLiteralAst, IsaAst, MultiVariableAssignmentAst, MultiVariableDeclarationAst, NoopAst, ParenExpressionAst, ParseTimeDetectedTypeError, PcAssignmentAst, PostDecrementExpressionAst, PostIncrementExpressionAst, ReplicationExpressionAst, ReturnExpressionAst, ReturnStatementAst, SignCastAst, StatementAst, StringLiteralAst, StructDefinitionAst, TernaryOperatorExpressionAst, TrueExpressionAst, UnaryOperatorExpressionAst, UserTypeNameAst, VariableAssignmentAst, VariableDeclarationAst, VariableDeclarationWithInitializationAst, WidthRevealAst
Defined Under Namespace
Classes: InternalError, LinesDescriptor, TypeError, ValueError
Constant Summary collapse
- Bits1Type =
Type.new(:bits, width: 1, qualifiers: [:known].freeze).freeze
- PossiblyUnknownBits1Type =
Type.new(:bits, width: 1).freeze
- Bits32Type =
Type.new(:bits, width: 32, qualifiers: [:known].freeze).freeze
- PossiblyUnknownBits32Type =
Type.new(:bits, width: 32).freeze
- Bits64Type =
Type.new(:bits, width: 64, qualifiers: [:known].freeze).freeze
- PossiblyUnknownBits64Type =
Type.new(:bits, width: 64).freeze
- ConstBoolType =
Type.new(:boolean, qualifiers: [:const]).freeze
- BoolType =
Type.new(:boolean).freeze
- VoidType =
Type.new(:void).freeze
- StringType =
Type.new(:string).freeze
- ReachableFunctionCacheType =
T.type_alias { T::Hash[T::Array[T.untyped], T::Array[FunctionDefAst]] }
Class Attribute Summary collapse
-
.value_error_ast ⇒ Object
Returns the value of attribute value_error_ast.
-
.value_error_reason ⇒ Object
Returns the value of attribute value_error_reason.
Instance Attribute Summary collapse
-
#children ⇒ Object
readonly
Returns the value of attribute children.
-
#input ⇒ Object
readonly
Returns the value of attribute input.
-
#interval ⇒ Object
readonly
Returns the value of attribute interval.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
Class Method Summary collapse
- .extract_base_var_name(node) ⇒ Object
- .from_h(yaml, source_mapper) ⇒ Object
- .input_from_source_yaml(yaml, source_mapper) ⇒ Object
- .interval_from_source_yaml(yaml) ⇒ Object
- .value_else(value_result, &_block) ⇒ Object
- .value_error(reason, ast = nil) ⇒ Object
- .value_try(&block) ⇒ Object
- .write_back_nested(target, new_value, symtab) ⇒ Object
Instance Method Summary collapse
- #always_terminates? ⇒ Boolean
- #const_eval?(symtab) ⇒ Boolean
- #declaration? ⇒ Boolean
- #executable? ⇒ Boolean
- #find_ancestor(klass) ⇒ Object
- #find_dst_registers(symtab) ⇒ Object
- #find_referenced_csrs ⇒ Object
- #find_src_registers(symtab) ⇒ Object
- #freeze_tree(global_symtab) ⇒ Object
- #gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
-
#gen_option_adoc ⇒ String
Generates asciidoc to document an implementation option.
-
#initialize(input, interval, children) ⇒ AstNode
constructor
A new instance of AstNode.
- #input_file ⇒ Object
- #inspect ⇒ Object
- #internal_error(reason) ⇒ Object
- #lineno ⇒ Object
- #lines_around ⇒ Object
- #nullify_assignments(symtab) ⇒ Object
- #pass_find_return_values(values, current_conditions) ⇒ Object
- #path ⇒ Object
- #print_ast(indent = 0, indent_size: 2, io: $stdout) ⇒ Object
-
#prune(symtab, forced_type: nil) ⇒ Object
forced_type, when not nil, is the type that the pruned result must be if is used when pruning expressions to ensure that the prune doesn’t change bit width just because a value is known and would fit in something smaller.
-
#reachable_exceptions(symtab, cache = {}) ⇒ Array<FunctionBodyAst>
List of all functions that can be reached (via function calls) from this node.
- #reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) ⇒ Object
- #set_input_file(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil) ⇒ Object
- #set_input_file_unless_already_set(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil) ⇒ Object
- #source_line_file_offsets ⇒ Object
- #source_starting_offset ⇒ Object
- #source_yaml ⇒ Object
- #starting_line ⇒ Object
- #text_value ⇒ Object
- #to_h ⇒ Object
- #to_idl ⇒ Object
- #truncation_warn(reason) ⇒ Object
- #type_check(symtab, strict:) ⇒ Object
- #type_error(reason) ⇒ Object
- #unindent(s) ⇒ Object
- #value_else(value_result, &block) ⇒ Object
- #value_error(reason) ⇒ Object
- #value_try(&block) ⇒ Object
Constructor Details
#initialize(input, interval, children) ⇒ AstNode
Returns a new instance of AstNode.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/idlc/ast.rb', line 231 def initialize(input, interval, children) @input = input @input_file = nil @starting_line = 0 @starting_offset = 0 @line_file_offsets = T.let(nil, T.nilable(T::Array[Integer])) @interval = interval @interval_text_value = unless input.nil? || interval.nil? input[interval] end @children = children @parent = nil # will be set later unless this is the root @children.each { |child| child.instance_variable_set(:@parent, self) } end |
Class Attribute Details
.value_error_ast ⇒ Object
Returns the value of attribute value_error_ast.
419 420 421 |
# File 'lib/idlc/ast.rb', line 419 def value_error_ast @value_error_ast end |
.value_error_reason ⇒ Object
Returns the value of attribute value_error_reason.
419 420 421 |
# File 'lib/idlc/ast.rb', line 419 def value_error_reason @value_error_reason end |
Instance Attribute Details
#children ⇒ Object (readonly)
Returns the value of attribute children.
99 100 101 |
# File 'lib/idlc/ast.rb', line 99 def children @children end |
#input ⇒ Object (readonly)
Returns the value of attribute input.
80 81 82 |
# File 'lib/idlc/ast.rb', line 80 def input @input end |
#interval ⇒ Object (readonly)
Returns the value of attribute interval.
84 85 86 |
# File 'lib/idlc/ast.rb', line 84 def interval @interval end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
95 96 97 |
# File 'lib/idlc/ast.rb', line 95 def parent @parent end |
Class Method Details
.extract_base_var_name(node) ⇒ Object
426 427 428 429 430 431 432 433 434 435 |
# File 'lib/idlc/ast.rb', line 426 def self.extract_base_var_name(node) case node when IdAst node.name when AryElementAccessAst, AryRangeAccessAst extract_base_var_name(node.var) else nil end end |
.from_h(yaml, source_mapper) ⇒ Object
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
# File 'lib/idlc/ast.rb', line 655 def self.from_h(yaml, source_mapper) case yaml.fetch("kind") when "array_access" then AryElementAccessAst.from_h(yaml, source_mapper) when "array_element_assignment" then AryElementAssignmentAst.from_h(yaml, source_mapper) when "array_includes_funcall" then ArrayIncludesAst.from_h(yaml, source_mapper) when "array_literal" then ArrayLiteralAst.from_h(yaml, source_mapper) when "array_range_access" then AryRangeAccessAst.from_h(yaml, source_mapper) when "array_range_assignment" then AryRangeAssignmentAst.from_h(yaml, source_mapper) when "array_size_funcall" then ArraySizeAst.from_h(yaml, source_mapper) when "binary_operator_expr" then BinaryExpressionAst.from_h(yaml, source_mapper) when "bitfield_decl" then BitfieldDefinitionAst.from_h(yaml, source_mapper) when "bitfield_field_decl" then BitfieldFieldDefinitionAst.from_h(yaml, source_mapper) when "bits_cast" then BitsCastAst.from_h(yaml, source_mapper) when "bits_literal" then IntLiteralAst.from_h(yaml, source_mapper) when "bits_to_enum_cast" then EnumCastAst.from_h(yaml, source_mapper) when "bits_type" then BuiltinTypeNameAst.from_h(yaml, source_mapper) when "bits_width_cast" then WidthRevealAst.from_h(yaml, source_mapper) when "builtin_enum_decl" then BuiltinEnumDefinitionAst.from_h(yaml, source_mapper) when "builtin_type" then BuiltinTypeNameAst.from_h(yaml, source_mapper) when "builtin_var_expr" then BuiltinVariableAst.from_h(yaml, source_mapper) when "comment" then CommentAst.from_h(yaml, source_mapper) when "concat_expr" then ConcatenationExpressionAst.from_h(yaml, source_mapper) when "conditional_stmt" then yaml.fetch("expr").fetch("kind") == "return_expr" ? ConditionalReturnStatementAst.from_h(yaml, source_mapper) : ConditionalStatementAst.from_h(yaml, source_mapper) when "constraint_body" then ConstraintBodyAst.from_h(yaml, source_mapper) when "csr_access_expr" then CsrWriteAst.from_h(yaml, source_mapper) when "csr_field_assignment" then CsrFieldAssignmentAst.from_h(yaml, source_mapper) when "csr_field_read_expr" then CsrFieldReadExpressionAst.from_h(yaml, source_mapper) when "csr_funcall_expr" then CsrFunctionCallAst.from_h(yaml, source_mapper) when "csr_read_expr" then CsrReadExpressionAst.from_h(yaml, source_mapper) when "csr_sw_write_expr" then CsrSoftwareWriteAst.from_h(yaml, source_mapper) when "dont_care" then DontCareReturnAst.from_h(yaml, source_mapper) when "dont_care_lval" then DontCareLvalueAst.from_h(yaml, source_mapper) when "else_if_stmt" then ElseIfAst.from_h(yaml, source_mapper) when "enum_decl" then EnumDefinitionAst.from_h(yaml, source_mapper) when "enum_element_size_funcall" then EnumElementSizeAst.from_h(yaml, source_mapper) when "enum_reference_expr" then EnumRefAst.from_h(yaml, source_mapper) when "enum_size_funcall" then EnumSizeAst.from_h(yaml, source_mapper) when "enum_to_array_cast" then EnumArrayCastAst.from_h(yaml, source_mapper) when "false" then FalseExpressionAst.from_h(yaml, source_mapper) when "field_access_expr" then FieldAccessExpressionAst.from_h(yaml, source_mapper) when "field_assignment" then FieldAssignmentAst.from_h(yaml, source_mapper) when "fetch_decl" then FetchAst.from_h(yaml, source_mapper) when "for_loop_stmt" then ForLoopAst.from_h(yaml, source_mapper) when "funcall_expr" then FunctionCallExpressionAst.from_h(yaml, source_mapper) when "function_body" then FunctionBodyAst.from_h(yaml, source_mapper) when "function_decl" then FunctionDefAst.from_h(yaml, source_mapper) when "id" then IdAst.from_h(yaml, source_mapper) when "if_body" then IfBodyAst.from_h(yaml, source_mapper) when "if_stmt" then IfAst.from_h(yaml, source_mapper) when "implication_expr" then ImplicationExpressionAst.from_h(yaml, source_mapper) when "implication_stmt" then ImplicationStatementAst.from_h(yaml, source_mapper) when "isa" then IsaAst.from_h(yaml, source_mapper) when "global_var_decl_with_init" then GlobalWithInitializationAst.from_h(yaml, source_mapper) when "global_var_decl" then GlobalAst.from_h(yaml, source_mapper) when "multi_var_assignment" then MultiVariableAssignmentAst.from_h(yaml, source_mapper) when "multi_var_decl" then MultiVariableDeclarationAst.from_h(yaml, source_mapper) when "noop_expr" then NoopAst.from_h(yaml, source_mapper) when "paren_expr" then ParenExpressionAst.from_h(yaml, source_mapper) when "pc_assignment" then PcAssignmentAst.from_h(yaml, source_mapper) when "post_decrement_expr" then PostDecrementExpressionAst.from_h(yaml, source_mapper) when "post_increment_expr" then PostIncrementExpressionAst.from_h(yaml, source_mapper) when "repl_expr" then ReplicationExpressionAst.from_h(yaml, source_mapper) when "return_expr" then ReturnExpressionAst.from_h(yaml, source_mapper) when "sign_cast" then SignCastAst.from_h(yaml, source_mapper) when "stmt" then yaml.fetch("expr").fetch("kind") == "return_expr" ? ReturnStatementAst.from_h(yaml, source_mapper) : StatementAst.from_h(yaml, source_mapper) when "string_literal" then StringLiteralAst.from_h(yaml, source_mapper) when "struct_decl" then StructDefinitionAst.from_h(yaml, source_mapper) when "ternary_operator_expr" then TernaryOperatorExpressionAst.from_h(yaml, source_mapper) when "true" then TrueExpressionAst.from_h(yaml, source_mapper) when "unary_operator_expr" then UnaryOperatorExpressionAst.from_h(yaml, source_mapper) when "user_type_reference" then UserTypeNameAst.from_h(yaml, source_mapper) when "var_assignment" then VariableAssignmentAst.from_h(yaml, source_mapper) when "var_decl" then VariableDeclarationAst.from_h(yaml, source_mapper) when "var_decl_init" then VariableDeclarationWithInitializationAst.from_h(yaml, source_mapper) else raise "Bad YAML kind: '#{yaml.fetch("kind")}'" end end |
.input_from_source_yaml(yaml, source_mapper) ⇒ Object
641 642 643 644 |
# File 'lib/idlc/ast.rb', line 641 def self.input_from_source_yaml(yaml, source_mapper) f = yaml.fetch("file") source_mapper.key?(f) ? source_mapper.fetch(f) : nil end |
.interval_from_source_yaml(yaml) ⇒ Object
647 648 649 |
# File 'lib/idlc/ast.rb', line 647 def self.interval_from_source_yaml(yaml) yaml.fetch("begin")...yaml.fetch("end") end |
.value_else(value_result, &_block) ⇒ Object
204 205 206 207 208 |
# File 'lib/idlc/ast.rb', line 204 def self.value_else(value_result, &_block) return unless value_result == :unknown_value yield end |
.value_error(reason, ast = nil) ⇒ Object
478 479 480 481 482 483 484 485 |
# File 'lib/idlc/ast.rb', line 478 def self.value_error(reason, ast = nil) AstNode.value_error_reason = reason AstNode.value_error_ast = ast # warn reason # warn "At #{ast.input_file}:#{ast.lineno}" unless ast.nil? throw(:value_error, :unknown_value) #raise AstNode::ValueError.new(lineno, input_file, reason), reason, [] end |
.value_try(&block) ⇒ Object
197 198 199 |
# File 'lib/idlc/ast.rb', line 197 def self.value_try(&block) catch(:value_error, &block) end |
.write_back_nested(target, new_value, symtab) ⇒ Object
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/idlc/ast.rb', line 444 def self.write_back_nested(target, new_value, symtab) case target when IdAst # Base case: simple variable existing_var = symtab.get(target.name) raise InternalError, "write_back_nested: '#{target.name}' not found in symbol table" if existing_var.nil? existing_var.value = new_value when AryElementAccessAst # Recursive case: v[idx] = val # Read parent, modify element, write back parent parent_value = target.var.value(symtab) idx_val = target.index.value(symtab) parent_value[idx_val] = new_value # Recursively write back the parent (which may itself be nested) write_back_nested(target.var, parent_value, symtab) when AryRangeAccessAst # Recursive case: v[msb:lsb] = new_value # Read parent, splice new_value into [msb:lsb], write parent back parent_value = T.cast(target.var.value(symtab), Integer) msb_val = T.cast(target.msb.value(symtab), Integer) lsb_val = T.cast(target.lsb.value(symtab), Integer) mask = ((1 << (msb_val - lsb_val + 1)) - 1) << lsb_val updated_parent = (parent_value & ~mask) | ((T.cast(new_value, Integer) << lsb_val) & mask) write_back_nested(target.var, updated_parent, symtab) else raise InternalError, "Unknown target type for write-back: #{target.class.name}" end end |
Instance Method Details
#always_terminates? ⇒ Boolean
100 |
# File 'lib/idlc/passes/prune.rb', line 100 def always_terminates? = false |
#const_eval?(symtab) ⇒ Boolean
217 |
# File 'lib/idlc/ast.rb', line 217 def const_eval?(symtab); end |
#declaration? ⇒ Boolean
225 |
# File 'lib/idlc/ast.rb', line 225 def declaration? = false |
#executable? ⇒ Boolean
221 |
# File 'lib/idlc/ast.rb', line 221 def executable? = false |
#find_ancestor(klass) ⇒ Object
295 296 297 298 299 300 301 302 303 |
# File 'lib/idlc/ast.rb', line 295 def find_ancestor(klass) if @parent.nil? nil elsif @parent.is_a?(klass) @parent else @parent.find_ancestor(klass) end end |
#find_dst_registers(symtab) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/idlc/passes/find_src_registers.rb', line 29 def find_dst_registers(symtab) # if executable? # value_result = value_try do # execute(symtab) # end # value_else(value_result) do # execute_unknown(symtab) # end # end add_symbol(symtab) if declaration? srcs = [] @children.each do |child| srcs.concat(child.find_dst_registers(symtab)) end srcs.uniq end |
#find_referenced_csrs ⇒ Object
13 14 15 16 17 18 19 |
# File 'lib/idlc/passes/find_referenced_csrs.rb', line 13 def find_referenced_csrs csrs = T.let([], T::Array[String]) @children.each do |child| csrs += child.find_referenced_csrs end csrs.uniq end |
#find_src_registers(symtab) ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/idlc/passes/find_src_registers.rb', line 11 def find_src_registers(symtab) # if executable? # value_result = value_try do # execute(symtab) # end # value_else(value_result) do # execute_unknown(symtab) # end # end add_symbol(symtab) if declaration? srcs = [] @children.each do |child| srcs.concat(child.find_src_registers(symtab)) end srcs.uniq end |
#freeze_tree(global_symtab) ⇒ Object
520 521 522 523 524 525 |
# File 'lib/idlc/ast.rb', line 520 def freeze_tree(global_symtab) return self if frozen? @children.each { |child| child.freeze_tree(global_symtab) } freeze end |
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
10 11 12 |
# File 'lib/idlc/passes/gen_adoc.rb', line 10 def gen_adoc(indent = 0, indent_spaces: 2) internal_error "must implement gen_adoc for #{self.class.name}" end |
#gen_option_adoc ⇒ String
Generates asciidoc to document an implementation option.
The result is not IDL code, but pretty-ified Asciidoc for document layout
16 17 18 |
# File 'lib/idlc/passes/gen_option_adoc.rb', line 16 def gen_option_adoc internal_error "must implement gen_option_adoc for #{self.class.name}" end |
#input_file ⇒ Object
68 69 70 |
# File 'lib/idlc/ast.rb', line 68 def input_file @input_file || @parent&.input_file end |
#inspect ⇒ Object
735 |
# File 'lib/idlc/ast.rb', line 735 def inspect = self.class.name.to_s |
#internal_error(reason) ⇒ Object
406 407 408 409 410 411 412 413 414 |
# File 'lib/idlc/ast.rb', line 406 def internal_error(reason) msg = <<~WHAT In file #{input_file} On line #{lineno} An internal error occurred #{reason} WHAT raise AstNode::InternalError, msg end |
#lineno ⇒ Object
288 289 290 |
# File 'lib/idlc/ast.rb', line 288 def lineno T.must(T.must(input)[0..T.must(interval).first]).count("\n") + 1 + starting_line end |
#lines_around ⇒ Object
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'lib/idlc/ast.rb', line 313 def lines_around cnt = 0 interval_start = T.must(interval).min while cnt < 2 cnt += 1 if T.must(input)[interval_start] == "\n" break if interval_start.zero? interval_start -= 1 end cnt = 0 interval_end = T.must(interval).max while cnt < 3 cnt += 1 if T.must(input)[interval_end] == "\n" break if interval_end >= (T.must(input).size - 1) break if cnt == 3 interval_end += 1 end LinesDescriptor.new( lines: T.must(T.must(input)[interval_start..interval_end]), problem_interval: (T.must(interval).min - interval_start..T.must(interval).max - interval_start), lines_interval: (interval_start + 1)..interval_end ) end |
#nullify_assignments(symtab) ⇒ Object
124 125 126 |
# File 'lib/idlc/passes/prune.rb', line 124 def nullify_assignments(symtab) children.each { |child| child.nullify_assignments(symtab) } end |
#pass_find_return_values(values, current_conditions) ⇒ Object
11 12 13 14 15 |
# File 'lib/idlc/passes/find_return_values.rb', line 11 def pass_find_return_values(values, current_conditions) children.each do |c| c.pass_find_return_values(values, current_conditions) end end |
#path ⇒ Object
529 530 531 532 533 534 535 |
# File 'lib/idlc/ast.rb', line 529 def path if @parent.nil? "#{self.class.name}" else "#{@parent.path}.#{self.class.name}" end end |
#print_ast(indent = 0, indent_size: 2, io: $stdout) ⇒ Object
506 507 508 509 510 511 |
# File 'lib/idlc/ast.rb', line 506 def print_ast(indent = 0, indent_size: 2, io: $stdout) io.puts "#{' ' * indent}#{self.class.name}:" children.each do |node| node.print_ast(indent + indent_size, indent_size:) end end |
#prune(symtab, forced_type: nil) ⇒ Object
forced_type, when not nil, is the type that the pruned result must be if is used when pruning expressions to ensure that the prune doesn’t change bit width just because a value is known and would fit in something smaller
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/idlc/passes/prune.rb', line 105 def prune(symtab, forced_type: nil) new_children = children.map { |child| child.prune(symtab, forced_type:) } if executable? value_try do execute(symtab) end # value_else: execute raised ValueError; symtab state is already correct end add_symbol(symtab) if declaration? # avoid allocation when nothing changed return self if !frozen? && new_children.each_with_index.all? { |c, i| c.equal?(children[i]) } new_node = dup new_node.instance_variable_set(:@children, new_children) new_node end |
#reachable_exceptions(symtab, cache = {}) ⇒ Array<FunctionBodyAst>
Returns List of all functions that can be reached (via function calls) from this node.
13 14 15 16 17 18 19 20 21 |
# File 'lib/idlc/passes/reachable_exceptions.rb', line 13 def reachable_exceptions(symtab, cache = {}) return 0 if @children.empty? mask = 0 @children.size.times do |i| mask |= @children[i].reachable_exceptions(symtab, cache) end mask end |
#reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/idlc/passes/reachable_functions.rb', line 18 def reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) seen = {} children.each_with_object([]) do |child, result| child.reachable_functions(symtab, cache).each do |fn| unless seen.key?(fn.name) seen[fn.name] = true result << fn end end end end |
#set_input_file(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil) ⇒ Object
279 280 281 282 283 284 |
# File 'lib/idlc/ast.rb', line 279 def set_input_file(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil) @input_file = Pathname.new(filename) @starting_line = starting_line @starting_offset = starting_offset @line_file_offsets = line_file_offsets end |
#set_input_file_unless_already_set(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil) ⇒ Object
263 264 265 266 267 268 269 270 |
# File 'lib/idlc/ast.rb', line 263 def set_input_file_unless_already_set(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil) return unless @input_file.nil? @input_file = Pathname.new(filename) @starting_line = starting_line @starting_offset = starting_offset @line_file_offsets = line_file_offsets end |
#source_line_file_offsets ⇒ Object
609 610 611 612 |
# File 'lib/idlc/ast.rb', line 609 def source_line_file_offsets return @line_file_offsets unless @line_file_offsets.nil? @parent&.source_line_file_offsets end |
#source_starting_offset ⇒ Object
604 605 606 |
# File 'lib/idlc/ast.rb', line 604 def source_starting_offset @starting_offset || @parent&.source_starting_offset || 0 end |
#source_yaml ⇒ Object
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
# File 'lib/idlc/ast.rb', line 569 def source_yaml base_offset = source_starting_offset interval_begin = T.must(interval).begin interval_end = T.must(interval).size == 0 ? T.must(interval).begin + 1 : T.must(interval).end lfo = source_line_file_offsets if lfo # Map an IDL-string position to a file byte offset using the per-line table. # Each entry lfo[i] is the file offset of the first character of IDL line i. # For position p: find the line it's on, then add the column within that line. file_begin = idl_pos_to_file_offset(interval_begin, lfo) # Find the last non-whitespace character in the interval so that end points to # real content and stays within file bounds. # For zero-size intervals, use interval_begin + 1 (matching the non-lfo path). inp = T.must(input) if T.must(interval).size == 0 last_char = interval_begin + 1 else last_char = interval_end - 1 last_char -= 1 while last_char > interval_begin && inp[last_char] =~ /\s/ end file_end = idl_pos_to_file_offset(last_char, lfo) else file_begin = base_offset + interval_begin file_end = base_offset + interval_end end { "file" => T.must(input_file).to_s, "begin" => file_begin, "end" => file_end } end |
#starting_line ⇒ Object
74 75 76 |
# File 'lib/idlc/ast.rb', line 74 def starting_line @starting_line || @parent&.starting_line || 0 end |
#text_value ⇒ Object
88 89 90 |
# File 'lib/idlc/ast.rb', line 88 def text_value T.must(@interval_text_value) end |
#to_h ⇒ Object
652 |
# File 'lib/idlc/ast.rb', line 652 def to_h; end |
#to_idl ⇒ Object
561 |
# File 'lib/idlc/ast.rb', line 561 def to_idl; end |
#truncation_warn(reason) ⇒ Object
341 342 343 344 345 346 347 348 349 350 |
# File 'lib/idlc/ast.rb', line 341 def truncation_warn(reason) msg = <<~WHAT In file #{input_file} On line #{lineno} A value was truncated #{reason}. Perhaps you want to use a widening operator (`+, `-, `*, `<<)? WHAT warn msg end |
#type_check(symtab, strict:) ⇒ Object
551 |
# File 'lib/idlc/ast.rb', line 551 def type_check(symtab, strict:); end |
#type_error(reason) ⇒ Object
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/idlc/ast.rb', line 357 def type_error(reason) lines_desc = lines_around lines = lines_desc.lines problem_interval = lines_desc.problem_interval lines_interval = lines_desc.lines_interval lines = if $stdout.isatty [ lines[0...problem_interval.min], "\u001b[31m", lines[problem_interval], "\u001b[0m", lines[(problem_interval.max + 1)..] ].join("") else [ lines[0...problem_interval.min], "**HERE** >> ", lines[problem_interval], " << **HERE**", lines[(problem_interval.max + 1)..] ].join("") end starting_lineno = T.must(T.must(input)[0..lines_interval.min]).count("\n") lines = lines.lines.map do |line| starting_lineno += 1 "#{starting_line + starting_lineno - 1}: #{line}" end.join("") msg = <<~WHAT In file #{input_file} On line #{lineno} In the code: #{lines.gsub("\n", "\n ")} A type error occurred #{$stdout.isatty ? "\u001b[31m#{reason}\u001b[0m" : reason} WHAT raise AstNode::TypeError, msg end |
#unindent(s) ⇒ Object
496 497 498 |
# File 'lib/idlc/ast.rb', line 496 def unindent(s) s.gsub(%r{^#{s.scan(/^[ \t]+(?=\S)/).min}}, "") end |
#value_else(value_result, &block) ⇒ Object
211 |
# File 'lib/idlc/ast.rb', line 211 def value_else(value_result, &block) = self.class.value_else(value_result, &block) |
#value_error(reason) ⇒ Object
487 |
# File 'lib/idlc/ast.rb', line 487 def value_error(reason) = self.class.value_error(reason, self) |
#value_try(&block) ⇒ Object
201 |
# File 'lib/idlc/ast.rb', line 201 def value_try(&block) = self.class.value_try(&block) |