Clean up parsing code.
This commit is contained in:
parent
c6319e7920
commit
fa00bda8ab
169
src/chalk.cr
169
src/chalk.cr
|
@ -2,170 +2,11 @@ require "./chalk/*"
|
|||
|
||||
module Chalk
|
||||
lexer = Lexer.new
|
||||
parser = Parser.new
|
||||
|
||||
tokens = lexer.lex(File.read("test.txt"))
|
||||
|
||||
def self.create_op(atom, op)
|
||||
pl = PlaceholderParser(Tree).new
|
||||
recurse = atom.then(op).then(pl).transform do |arr|
|
||||
arr = arr.flatten
|
||||
TreeOp.new(
|
||||
arr[1].as(Token).type,
|
||||
arr[0].as(Tree),
|
||||
arr[2].as(Tree)).as(Tree)
|
||||
end
|
||||
pl.parser = either(recurse, atom)
|
||||
return pl
|
||||
trees = parser.parse?(tokens)
|
||||
trees.try do |trees|
|
||||
trees.each &.accept(PrintVisitor.new)
|
||||
end
|
||||
|
||||
def self.create_ops(source, ops)
|
||||
ops.reduce(source) do |previous, current|
|
||||
create_op(previous, current)
|
||||
end
|
||||
end
|
||||
|
||||
def self.create_type
|
||||
either(type(TokenType::KwU0), type(TokenType::KwU8), type(TokenType::KwU12))
|
||||
end
|
||||
|
||||
def self.create_lit
|
||||
dec_parser = type(TokenType::LitDec).transform &.string.to_i64
|
||||
hex_parser = type(TokenType::LitHex).transform &.string.lchop("0x").to_i64(16)
|
||||
bin_parser = type(TokenType::LitBin).transform &.string.lchop("0b").to_i64(2)
|
||||
lit_parser = either(dec_parser, hex_parser, bin_parser).transform { |it| TreeLit.new(it).as(Tree) }
|
||||
return lit_parser
|
||||
end
|
||||
|
||||
def self.create_call(expr)
|
||||
call = type(TokenType::Id).then(char '(').then(delimited(expr, char ',')).then(char ')').transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[0].as(Token).string
|
||||
params = arr[2..arr.size - 2].map &.as(Tree)
|
||||
TreeCall.new(name, params).as(Tree)
|
||||
end
|
||||
return call
|
||||
end
|
||||
|
||||
def self.create_block(statement)
|
||||
block = char('{').then(many(statement)).then(char '}').transform do |arr|
|
||||
arr = arr.flatten
|
||||
params = arr[1..arr.size - 2].map &.as(Tree)
|
||||
TreeBlock.new(params).as(Tree)
|
||||
end
|
||||
return block
|
||||
end
|
||||
|
||||
def self.create_if(expr, block)
|
||||
iff = type(TokenType::KwIf).then(char '(').then(expr).then(char ')').then(block)
|
||||
.then(optional(type(TokenType::KwElse).then(block)))
|
||||
.transform do |arr|
|
||||
arr = arr.flatten
|
||||
cond = arr[2].as(Tree)
|
||||
code = arr[4].as(Tree)
|
||||
otherwise = arr.size == 7 ? arr[6].as(Tree) : nil
|
||||
TreeIf.new(cond, code, otherwise).as(Tree)
|
||||
end
|
||||
return iff
|
||||
end
|
||||
|
||||
def self.create_while(expr, block)
|
||||
whilee = type(TokenType::KwWhile).then(char '(').then(expr).then(char ')').then(block).transform do |arr|
|
||||
arr = arr.flatten
|
||||
cond = arr[2].as(Tree)
|
||||
code = arr[4].as(Tree)
|
||||
TreeWhile.new(cond, code).as(Tree)
|
||||
end
|
||||
return whilee
|
||||
end
|
||||
|
||||
def self.create_return(expr)
|
||||
returnn = type(TokenType::KwReturn).then(expr).then(char ';').transform do |arr|
|
||||
arr = arr.flatten
|
||||
value = arr[1].as(Tree)
|
||||
TreeReturn.new(value).as(Tree)
|
||||
end
|
||||
return returnn
|
||||
end
|
||||
|
||||
def self.create_func(block, type)
|
||||
func = type(TokenType::KwFun).then(type(TokenType::Id))
|
||||
.then(char '(').then(delimited(type(TokenType::Id), char ',')).then(char ')')
|
||||
.then(char ':').then(type)
|
||||
.then(block).transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[1].as(Token).string
|
||||
params = arr[3..arr.size - 5].map &.as(Token).string
|
||||
code = arr[arr.size - 1].as(Tree)
|
||||
type = arr[arr.size - 2].as(Token).type
|
||||
TreeFunction.new(name, params, code).as(Tree)
|
||||
end
|
||||
return func
|
||||
end
|
||||
|
||||
def self.create_var(expr)
|
||||
var = type(TokenType::KwVar).then(type(TokenType::Id)).then(char '=').then(expr).then(char ';').transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[1].as(Token).string
|
||||
exp = arr[arr.size - 2].as(Tree)
|
||||
TreeVar.new(name, exp).as(Tree)
|
||||
end
|
||||
return var
|
||||
end
|
||||
|
||||
def self.create_assign(expr)
|
||||
assign = type(TokenType::Id).then(char '=').then(expr).then(char ';').transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[0].as(Token).string
|
||||
exp = arr[arr.size - 2].as(Tree)
|
||||
TreeAssign.new(name, exp).as(Tree)
|
||||
end
|
||||
return assign
|
||||
end
|
||||
|
||||
def self.create_basic(expr)
|
||||
basic = expr.then(char ';').transform do |arr|
|
||||
arr.flatten[0].as(Tree)
|
||||
end
|
||||
return basic
|
||||
end
|
||||
|
||||
def self.create_expression
|
||||
expr_place = PlaceholderParser(Tree).new
|
||||
literal = create_lit
|
||||
id = type(TokenType::Id).transform { |it| TreeId.new(it.string).as(Tree) }
|
||||
call = create_call(expr_place)
|
||||
atom = either(literal, call, id)
|
||||
|
||||
ops = [ either(type(TokenType::OpMul), type(TokenType::OpDiv)),
|
||||
either(type(TokenType::OpAdd), type(TokenType::OpSub)),
|
||||
type(TokenType::OpXor),
|
||||
type(TokenType::OpAnd),
|
||||
type(TokenType::OpOr) ]
|
||||
expr = create_ops(atom, ops)
|
||||
expr_place.parser = expr
|
||||
|
||||
return expr
|
||||
end
|
||||
|
||||
def self.create_block
|
||||
expr = create_expression
|
||||
|
||||
statement_place = PlaceholderParser(Tree).new
|
||||
block = create_block(statement_place)
|
||||
iff = create_if(expr, block)
|
||||
whilee = create_while(expr, block)
|
||||
returnn = create_return(expr)
|
||||
var = create_var(expr)
|
||||
assign = create_assign(expr)
|
||||
basic = create_basic(expr)
|
||||
statement = either(basic, var, assign, block, iff, whilee, returnn)
|
||||
statement_place.parser = statement
|
||||
|
||||
return block
|
||||
end
|
||||
|
||||
func = create_func(create_block, create_type)
|
||||
body = many(func)
|
||||
|
||||
final = body
|
||||
final.parse(tokens, 0)[0].each &.accept(PrintVisitor.new)
|
||||
end
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
require "./lexer.cr"
|
||||
require "./parser.cr"
|
||||
require "./parsers.cr"
|
||||
|
||||
module Chalk
|
||||
def self.type(type): Parser(Token)
|
||||
return TypeParser.new(type).as(Parser(Token))
|
||||
end
|
||||
module Builder
|
||||
def type(type): BasicParser(Token)
|
||||
return TypeParser.new(type).as(BasicParser(Token))
|
||||
end
|
||||
|
||||
def self.char(type): Parser(Token)
|
||||
return CharParser.new(type).as(Parser(Token))
|
||||
end
|
||||
def char(type): BasicParser(Token)
|
||||
return CharParser.new(type).as(BasicParser(Token))
|
||||
end
|
||||
|
||||
def self.transform(parser : Parser(T), &transform : T -> R) forall T, R
|
||||
return TransformParser.new(parser, &transform).as(Parser(R))
|
||||
end
|
||||
def transform(parser : BasicParser(T), &transform : T -> R) forall T, R
|
||||
return TransformParser.new(parser, &transform).as(BasicParser(R))
|
||||
end
|
||||
|
||||
def self.optional(parser : Parser(T)): Parser(T?) forall T
|
||||
return OptionalParser.new(parser).as(Parser(T?))
|
||||
end
|
||||
def optional(parser : BasicParser(T)): BasicParser(T?) forall T
|
||||
return OptionalParser.new(parser).as(BasicParser(T?))
|
||||
end
|
||||
|
||||
def self.either(*args : Parser(T)): Parser(T) forall T
|
||||
return EitherParser.new(args.to_a).as(Parser(T))
|
||||
end
|
||||
def either(*args : BasicParser(T)): BasicParser(T) forall T
|
||||
return EitherParser.new(args.to_a).as(BasicParser(T))
|
||||
end
|
||||
|
||||
def self.many(parser : Parser(T)): Parser(Array(T)) forall T
|
||||
return ManyParser.new(parser).as(Parser(Array(T)))
|
||||
end
|
||||
def many(parser : BasicParser(T)): BasicParser(Array(T)) forall T
|
||||
return ManyParser.new(parser).as(BasicParser(Array(T)))
|
||||
end
|
||||
|
||||
def self.delimited(parser : Parser(T), delimiter : Parser(R)): Parser(Array(T)) forall T, R
|
||||
return DelimitedParser.new(parser, delimiter).as(Parser(Array(T)))
|
||||
end
|
||||
def delimited(parser : BasicParser(T), delimiter : BasicParser(R)): BasicParser(Array(T)) forall T, R
|
||||
return DelimitedParser.new(parser, delimiter).as(BasicParser(Array(T)))
|
||||
end
|
||||
|
||||
def self.then(first : Parser(T), second : Parser(R)) forall T, R
|
||||
return NextParser.new(first, second).as(Parser(Array(T | R)))
|
||||
def then(first : BasicParser(T), second : BasicParser(R)) forall T, R
|
||||
return NextParser.new(first, second).as(BasicParser(Array(T | R)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,7 +72,7 @@ module Chalk
|
|||
|
||||
def lex(string)
|
||||
return @lexer.lex(string)
|
||||
.select { |t| t[0] != " " }
|
||||
.select { |t| !t[0][0].whitespace? }
|
||||
.map do |tuple|
|
||||
string, id = tuple
|
||||
Token.new(string, TokenType.new(id))
|
||||
|
|
|
@ -1,151 +1,173 @@
|
|||
require "./builder.cr"
|
||||
|
||||
module Chalk
|
||||
class Parser
|
||||
include Builder
|
||||
|
||||
abstract class Parser(T)
|
||||
abstract def parse?(tokens : Array(Token),
|
||||
index : Int64): Tuple(T, Int64)?
|
||||
def parse(tokens : Array(Token),
|
||||
index : Int64): Tuple(T, Int64)
|
||||
return parse?(tokens, index).not_nil!
|
||||
private def create_type
|
||||
either(type(TokenType::KwU0), type(TokenType::KwU8), type(TokenType::KwU12))
|
||||
end
|
||||
|
||||
def transform(&transform : T -> R) forall R
|
||||
return TransformParser.new(self, &transform).as(Parser(R))
|
||||
private def create_lit
|
||||
dec_parser = type(TokenType::LitDec).transform &.string.to_i64
|
||||
hex_parser = type(TokenType::LitHex).transform &.string.lchop("0x").to_i64(16)
|
||||
bin_parser = type(TokenType::LitBin).transform &.string.lchop("0b").to_i64(2)
|
||||
lit_parser = either(dec_parser, hex_parser, bin_parser).transform { |it| TreeLit.new(it).as(Tree) }
|
||||
return lit_parser
|
||||
end
|
||||
|
||||
def then(other : Parser(R)): Parser(Array(T | R)) forall R
|
||||
return NextParser
|
||||
.new(self, other)
|
||||
.as(Parser(Array(T | R)))
|
||||
end
|
||||
end
|
||||
|
||||
class TypeParser < Parser(Token)
|
||||
def initialize(@type : TokenType)
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
return nil unless index < tokens.size
|
||||
return nil unless tokens[index].type == @type
|
||||
return { tokens[index], index + 1}
|
||||
end
|
||||
end
|
||||
|
||||
class CharParser < Parser(Token)
|
||||
def initialize(@char : Char)
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
return nil unless index < tokens.size
|
||||
return nil unless (tokens[index].type == TokenType::Any) &&
|
||||
tokens[index].string[0] == @char
|
||||
return { tokens[index], index + 1}
|
||||
end
|
||||
end
|
||||
|
||||
class TransformParser(T, R) < Parser(R)
|
||||
def initialize(@parser : Parser(T), &@block : T -> R)
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
if parsed = @parser.parse?(tokens, index)
|
||||
return { @block.call(parsed[0]), parsed[1] }
|
||||
private def create_op_expr(atom, op)
|
||||
pl = PlaceholderParser(Tree).new
|
||||
recurse = atom.then(op).then(pl).transform do |arr|
|
||||
arr = arr.flatten
|
||||
TreeOp.new(
|
||||
arr[1].as(Token).type,
|
||||
arr[0].as(Tree),
|
||||
arr[2].as(Tree)).as(Tree)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
class OptionalParser(T) < Parser(T?)
|
||||
def initialize(@parser : Parser(T))
|
||||
pl.parser = either(recurse, atom)
|
||||
return pl
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
if parsed = @parser.parse?(tokens, index)
|
||||
return { parsed[0], parsed[1] }
|
||||
private def create_op_exprs(atom, ops)
|
||||
ops.reduce(atom) do |previous, current|
|
||||
create_op_expr(previous, current)
|
||||
end
|
||||
return { nil, index }
|
||||
end
|
||||
end
|
||||
|
||||
class EitherParser(T) < Parser(T)
|
||||
def initialize(@parsers : Array(Parser(T)))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
@parsers.each do |parser|
|
||||
if parsed = parser.parse?(tokens, index)
|
||||
return parsed
|
||||
end
|
||||
private def create_call(expr)
|
||||
call = type(TokenType::Id).then(char '(').then(delimited(expr, char ',')).then(char ')').transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[0].as(Token).string
|
||||
params = arr[2..arr.size - 2].map &.as(Tree)
|
||||
TreeCall.new(name, params).as(Tree)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
class ManyParser(T) < Parser(Array(T))
|
||||
def initialize(@parser : Parser(T))
|
||||
return call
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
many = [] of T
|
||||
while parsed = @parser.parse?(tokens, index)
|
||||
item, index = parsed
|
||||
many << item
|
||||
private def create_expr
|
||||
expr_place = PlaceholderParser(Tree).new
|
||||
literal = create_lit
|
||||
id = type(TokenType::Id).transform { |it| TreeId.new(it.string).as(Tree) }
|
||||
call = create_call(expr_place)
|
||||
atom = either(literal, call, id)
|
||||
|
||||
ops = [ either(type(TokenType::OpMul), type(TokenType::OpDiv)),
|
||||
either(type(TokenType::OpAdd), type(TokenType::OpSub)),
|
||||
type(TokenType::OpXor),
|
||||
type(TokenType::OpAnd),
|
||||
type(TokenType::OpOr) ]
|
||||
expr = create_op_exprs(atom, ops)
|
||||
expr_place.parser = expr
|
||||
|
||||
return expr
|
||||
end
|
||||
|
||||
private def create_var(expr)
|
||||
var = type(TokenType::KwVar).then(type(TokenType::Id)).then(char '=').then(expr).then(char ';').transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[1].as(Token).string
|
||||
exp = arr[arr.size - 2].as(Tree)
|
||||
TreeVar.new(name, exp).as(Tree)
|
||||
end
|
||||
return { many, index }
|
||||
end
|
||||
end
|
||||
|
||||
class DelimitedParser(T, R) < Parser(Array(T))
|
||||
def initialize(@parser : Parser(T), @delimiter : Parser(R))
|
||||
return var
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
array = [] of T
|
||||
first = @parser.parse?(tokens, index)
|
||||
return { array, index } unless first
|
||||
first_value, index = first
|
||||
array << first_value
|
||||
while delimiter = @delimiter.parse?(tokens, index)
|
||||
_, new_index = delimiter
|
||||
new = @parser.parse?(tokens, new_index)
|
||||
break unless new
|
||||
new_value, index = new
|
||||
array << new_value
|
||||
private def create_assign(expr)
|
||||
assign = type(TokenType::Id).then(char '=').then(expr).then(char ';').transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[0].as(Token).string
|
||||
exp = arr[arr.size - 2].as(Tree)
|
||||
TreeAssign.new(name, exp).as(Tree)
|
||||
end
|
||||
|
||||
return { array, index }
|
||||
end
|
||||
end
|
||||
|
||||
class NextParser(T, R) < Parser(Array(T | R))
|
||||
def initialize(@first : Parser(T), @second : Parser(R))
|
||||
return assign
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
first = @first.parse?(tokens, index)
|
||||
return nil unless first
|
||||
first_value, index = first
|
||||
|
||||
second = @second.parse?(tokens, index)
|
||||
return nil unless second
|
||||
second_value, index = second
|
||||
|
||||
array = Array(T | R).new
|
||||
array << first_value << second_value
|
||||
return { array, index }
|
||||
private def create_basic(expr)
|
||||
basic = expr.then(char ';').transform do |arr|
|
||||
arr.flatten[0].as(Tree)
|
||||
end
|
||||
return basic
|
||||
end
|
||||
end
|
||||
|
||||
class PlaceholderParser(T) < Parser(T)
|
||||
property parser : Parser(T)?
|
||||
private def create_if(expr, block)
|
||||
iff = type(TokenType::KwIf).then(char '(').then(expr).then(char ')').then(block)
|
||||
.then(optional(type(TokenType::KwElse).then(block)))
|
||||
.transform do |arr|
|
||||
arr = arr.flatten
|
||||
cond = arr[2].as(Tree)
|
||||
code = arr[4].as(Tree)
|
||||
otherwise = arr.size == 7 ? arr[6].as(Tree) : nil
|
||||
TreeIf.new(cond, code, otherwise).as(Tree)
|
||||
end
|
||||
return iff
|
||||
end
|
||||
|
||||
private def create_while(expr, block)
|
||||
whilee = type(TokenType::KwWhile).then(char '(').then(expr).then(char ')').then(block).transform do |arr|
|
||||
arr = arr.flatten
|
||||
cond = arr[2].as(Tree)
|
||||
code = arr[4].as(Tree)
|
||||
TreeWhile.new(cond, code).as(Tree)
|
||||
end
|
||||
return whilee
|
||||
end
|
||||
|
||||
private def create_return(expr)
|
||||
returnn = type(TokenType::KwReturn).then(expr).then(char ';').transform do |arr|
|
||||
arr = arr.flatten
|
||||
value = arr[1].as(Tree)
|
||||
TreeReturn.new(value).as(Tree)
|
||||
end
|
||||
return returnn
|
||||
end
|
||||
|
||||
private def create_block(statement)
|
||||
block = char('{').then(many(statement)).then(char '}').transform do |arr|
|
||||
arr = arr.flatten
|
||||
params = arr[1..arr.size - 2].map &.as(Tree)
|
||||
TreeBlock.new(params).as(Tree)
|
||||
end
|
||||
return block
|
||||
end
|
||||
|
||||
private def create_statement_block
|
||||
statement_place = PlaceholderParser(Tree).new
|
||||
expr = create_expr
|
||||
block = create_block(statement_place)
|
||||
iff = create_if(expr, block)
|
||||
whilee = create_while(expr, block)
|
||||
returnn = create_return(expr)
|
||||
var = create_var(expr)
|
||||
assign = create_assign(expr)
|
||||
basic = create_basic(expr)
|
||||
statement = either(basic, var, assign, block, iff, whilee, returnn)
|
||||
statement_place.parser = statement
|
||||
return {statement, block}
|
||||
end
|
||||
|
||||
private def create_func(block, type)
|
||||
func = type(TokenType::KwFun).then(type(TokenType::Id))
|
||||
.then(char '(').then(delimited(type(TokenType::Id), char ',')).then(char ')')
|
||||
.then(char ':').then(type)
|
||||
.then(block).transform do |arr|
|
||||
arr = arr.flatten
|
||||
name = arr[1].as(Token).string
|
||||
params = arr[3..arr.size - 5].map &.as(Token).string
|
||||
code = arr[arr.size - 1].as(Tree)
|
||||
type = arr[arr.size - 2].as(Token).type
|
||||
TreeFunction.new(name, params, code).as(Tree)
|
||||
end
|
||||
return func
|
||||
end
|
||||
|
||||
def initialize
|
||||
@parser = nil
|
||||
_, block = create_statement_block
|
||||
@parser = many(create_func(block, create_type)).as(BasicParser(Array(Tree)))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
@parser.try &.parse?(tokens, index)
|
||||
def parse?(tokens)
|
||||
return @parser.parse?(tokens, 0).try &.[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
151
src/chalk/parsers.cr
Normal file
151
src/chalk/parsers.cr
Normal file
|
@ -0,0 +1,151 @@
|
|||
require "./builder.cr"
|
||||
|
||||
module Chalk
|
||||
|
||||
abstract class BasicParser(T)
|
||||
abstract def parse?(tokens : Array(Token),
|
||||
index : Int64): Tuple(T, Int64)?
|
||||
def parse(tokens : Array(Token),
|
||||
index : Int64): Tuple(T, Int64)
|
||||
return parse?(tokens, index).not_nil!
|
||||
end
|
||||
|
||||
def transform(&transform : T -> R) forall R
|
||||
return TransformParser.new(self, &transform).as(BasicParser(R))
|
||||
end
|
||||
|
||||
def then(other : BasicParser(R)): BasicParser(Array(T | R)) forall R
|
||||
return NextParser
|
||||
.new(self, other)
|
||||
.as(BasicParser(Array(T | R)))
|
||||
end
|
||||
end
|
||||
|
||||
class TypeParser < BasicParser(Token)
|
||||
def initialize(@type : TokenType)
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
return nil unless index < tokens.size
|
||||
return nil unless tokens[index].type == @type
|
||||
return { tokens[index], index + 1}
|
||||
end
|
||||
end
|
||||
|
||||
class CharParser < BasicParser(Token)
|
||||
def initialize(@char : Char)
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
return nil unless index < tokens.size
|
||||
return nil unless (tokens[index].type == TokenType::Any) &&
|
||||
tokens[index].string[0] == @char
|
||||
return { tokens[index], index + 1}
|
||||
end
|
||||
end
|
||||
|
||||
class TransformParser(T, R) < BasicParser(R)
|
||||
def initialize(@parser : BasicParser(T), &@block : T -> R)
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
if parsed = @parser.parse?(tokens, index)
|
||||
return { @block.call(parsed[0]), parsed[1] }
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
class OptionalParser(T) < BasicParser(T?)
|
||||
def initialize(@parser : BasicParser(T))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
if parsed = @parser.parse?(tokens, index)
|
||||
return { parsed[0], parsed[1] }
|
||||
end
|
||||
return { nil, index }
|
||||
end
|
||||
end
|
||||
|
||||
class EitherParser(T) < BasicParser(T)
|
||||
def initialize(@parsers : Array(BasicParser(T)))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
@parsers.each do |parser|
|
||||
if parsed = parser.parse?(tokens, index)
|
||||
return parsed
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
class ManyParser(T) < BasicParser(Array(T))
|
||||
def initialize(@parser : BasicParser(T))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
many = [] of T
|
||||
while parsed = @parser.parse?(tokens, index)
|
||||
item, index = parsed
|
||||
many << item
|
||||
end
|
||||
return { many, index }
|
||||
end
|
||||
end
|
||||
|
||||
class DelimitedParser(T, R) < BasicParser(Array(T))
|
||||
def initialize(@parser : BasicParser(T), @delimiter : BasicParser(R))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
array = [] of T
|
||||
first = @parser.parse?(tokens, index)
|
||||
return { array, index } unless first
|
||||
first_value, index = first
|
||||
array << first_value
|
||||
while delimiter = @delimiter.parse?(tokens, index)
|
||||
_, new_index = delimiter
|
||||
new = @parser.parse?(tokens, new_index)
|
||||
break unless new
|
||||
new_value, index = new
|
||||
array << new_value
|
||||
end
|
||||
|
||||
return { array, index }
|
||||
end
|
||||
end
|
||||
|
||||
class NextParser(T, R) < BasicParser(Array(T | R))
|
||||
def initialize(@first : BasicParser(T), @second : BasicParser(R))
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
first = @first.parse?(tokens, index)
|
||||
return nil unless first
|
||||
first_value, index = first
|
||||
|
||||
second = @second.parse?(tokens, index)
|
||||
return nil unless second
|
||||
second_value, index = second
|
||||
|
||||
array = Array(T | R).new
|
||||
array << first_value << second_value
|
||||
return { array, index }
|
||||
end
|
||||
end
|
||||
|
||||
class PlaceholderParser(T) < BasicParser(T)
|
||||
property parser : BasicParser(T)?
|
||||
|
||||
def initialize
|
||||
@parser = nil
|
||||
end
|
||||
|
||||
def parse?(tokens, index)
|
||||
@parser.try &.parse?(tokens, index)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user