MycoBuilder: BasicObject
{
# TODO: be more clever here const ast: CodeTools::AST::Builder.new const escape_encodings: { hash = ::Ruby::Hash.new hash["\\a"] = 7.chr # \a 0x07 Bell or alert hash["\\b"] = 8.chr # \b 0x08 Backspace # TODO: # \cx Control-x # TODO: # \C-x Control-x hash["\\e"] = 27.chr # \e 0x1b Escape hash["\\f"] = 12.chr # \f 0x0c Formfeed # TODO: # \M-\C-x Meta-Control-x hash["\\n"] = 10.chr # \n 0x0a Newline # TODO: # \nnn Octal notation, where n is a digit hash["\\r"] = 13.chr # \r 0x0d Carriage return hash["\\s"] = 32.chr # \s 0x20 Space hash["\\t"] = 9.chr # \t 0x09 Tab hash["\\v"] = 11.chr # \v 0x0b Vertical tab # TODO: # \xnn Hexadecimal notation, where n is a digit hash } # Encode escape characters in string literals # TODO: rigorously test and refine encode_escapes: |str| { str.gsub(Regexp.new("\\\\.")) |substr| { escape_encodings.fetch(substr, substr[-1]) } } # Given a node,op list ([node, op, node, op, ... node]) and operator types, # collapse the (node, op, node) groups where the operator is one of the types # # This function is meant to be called several times on the same list, # with a different set of operator types each time, in order of precedence. # collapse: |input, *types, &block| { output = [] # Scan through, reducing or shifting based on the operator Loop.run { (input.count > 2) || Loop.break n0 = input.shift op = input.shift types.include?(op.type) &? ( n1 = input.shift result = block &? block.call(n0,op,n1) ?? ast.invoke(op, n0, op.sym, ast.args(n1, [n1])) input.unshift(result) ) ?? ( output.push(n0) output.push(op) ) } # Push the last item remaining output.push(input.shift) input.replace(output) }
}