Create draft of parser in main code.

This commit is contained in:
Danila Fedorin 2018-07-24 23:57:20 -07:00
parent e57ca6c172
commit c6319e7920
5 changed files with 239 additions and 6 deletions

View File

@ -1,6 +1,171 @@
require "./chalk/*"
# TODO: Write documentation for `Chalk`
module Chalk
# TODO: Put your code here
lexer = Lexer.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
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

View File

@ -6,6 +6,10 @@ module Chalk
return TypeParser.new(type).as(Parser(Token))
end
def self.char(type): Parser(Token)
return CharParser.new(type).as(Parser(Token))
end
def self.transform(parser : Parser(T), &transform : T -> R) forall T, R
return TransformParser.new(parser, &transform).as(Parser(R))
end
@ -22,6 +26,10 @@ module Chalk
return ManyParser.new(parser).as(Parser(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 self.then(first : Parser(T), second : Parser(R)) forall T, R
return NextParser.new(first, second).as(Parser(Array(T | R)))
end

View File

@ -32,6 +32,18 @@ module Chalk
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
@ -84,6 +96,28 @@ module Chalk
end
end
class DelimitedParser(T, R) < Parser(Array(T))
def initialize(@parser : Parser(T), @delimiter : Parser(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) < Parser(Array(T | R))
def initialize(@first : Parser(T), @second : Parser(R))
end
@ -111,7 +145,7 @@ module Chalk
end
def parse?(tokens, index)
@parser.try &.parse(tokens, index)
@parser.try &.parse?(tokens, index)
end
end
end

View File

@ -59,8 +59,10 @@ module Chalk
end
end
forward("[call]", TreeCall)
forward("[block]", TreeBlock)
forward("[var]", TreeVar)
forward("[assign]", TreeAssign)
forward("[if]", TreeIf)
forward("[while]", TreeWhile)
forward("[return]", TreeReturn)

View File

@ -24,6 +24,18 @@ module Chalk
def initialize(@lit : Int64) end
end
class TreeCall < Tree
property name : String
property params : Array(Tree)
def initialize(@name : String, @params : Array(Tree)) end
def accept(v : Visitor)
v.visit(self)
@params.each &.accept(v)
v.finish(self)
end
end
class TreeOp < Tree
property op : TokenType
property left : Tree
@ -73,17 +85,29 @@ module Chalk
end
end
class TreeAssign < Tree
property name : String
property expr : Tree
def initialize(@name : String, @expr : Tree) end
def accept(v : Visitor)
v.visit(self)
@expr.accept(v)
v.finish(self)
end
end
class TreeIf < Tree
property condition : Tree
property block : Tree
property otherwise : Tree
property otherwise : Tree?
def initialize(@condition : Tree, @block : Tree, @otherwise : Tree) end
def initialize(@condition : Tree, @block : Tree, @otherwise : Tree? = nil) end
def accept(v : Visitor)
v.visit(self)
@condition.accept(v)
@block.accept(v)
@otherwise.accept(v)
@otherwise.try &.accept(v)
v.finish(self)
end
end