Initial work on generics and fixed bugs in the parser with stropped operator names
This commit is contained in:
parent
4591e5ca0e
commit
e32b8e258f
|
@ -16,8 +16,8 @@ import meta/ast
|
||||||
import meta/errors
|
import meta/errors
|
||||||
import ../config
|
import ../config
|
||||||
import ../util/multibyte
|
import ../util/multibyte
|
||||||
import lexer
|
import lexer as l
|
||||||
import parser
|
import parser as p
|
||||||
|
|
||||||
import tables
|
import tables
|
||||||
import strformat
|
import strformat
|
||||||
|
@ -448,6 +448,9 @@ proc compareTypes(self: Compiler, a, b: Type): bool =
|
||||||
# since peon doesn't have return type
|
# since peon doesn't have return type
|
||||||
# inference
|
# inference
|
||||||
return true
|
return true
|
||||||
|
elif a.kind == Generic or b.kind == Generic:
|
||||||
|
# Matching generic argument types
|
||||||
|
return true
|
||||||
elif a.kind != b.kind:
|
elif a.kind != b.kind:
|
||||||
# Next, we see the type discriminant:
|
# Next, we see the type discriminant:
|
||||||
# If they're different, then they can't
|
# If they're different, then they can't
|
||||||
|
@ -801,7 +804,7 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
|
||||||
elif impl.len() > 1:
|
elif impl.len() > 1:
|
||||||
var msg = &"multiple matching implementations of '{name}' found:\n"
|
var msg = &"multiple matching implementations of '{name}' found:\n"
|
||||||
for fn in reversed(impl):
|
for fn in reversed(impl):
|
||||||
msg &= &"- '{fn.name}' at line {fn.line} of type {self.typeToStr(fn.valueType)}\n"
|
msg &= &"- '{fn.name.token.lexeme}' at line {fn.line} of type {self.typeToStr(fn.valueType)}\n"
|
||||||
self.error(msg)
|
self.error(msg)
|
||||||
return impl[0]
|
return impl[0]
|
||||||
|
|
||||||
|
@ -815,8 +818,9 @@ proc emitFunction(self: Compiler, name: Name) =
|
||||||
proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
|
proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
## Emits single instructions for builtin functions
|
## Emits single instructions for builtin functions
|
||||||
## such as addition or subtraction
|
## such as addition or subtraction
|
||||||
for argument in args:
|
if fn.builtinOp notin ["GenericLogicalOr", "GenericLogicalAnd"]:
|
||||||
self.expression(argument)
|
for argument in args:
|
||||||
|
self.expression(argument)
|
||||||
case fn.builtinOp:
|
case fn.builtinOp:
|
||||||
of "AddInt64":
|
of "AddInt64":
|
||||||
self.emitByte(AddInt64)
|
self.emitByte(AddInt64)
|
||||||
|
@ -898,6 +902,21 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
self.emitByte(DivFloat32)
|
self.emitByte(DivFloat32)
|
||||||
of "MulFloat32":
|
of "MulFloat32":
|
||||||
self.emitByte(MulFloat32)
|
self.emitByte(MulFloat32)
|
||||||
|
of "GenericLogicalOr":
|
||||||
|
self.expression(args[0])
|
||||||
|
let jump = self.emitJump(JumpIfTrue)
|
||||||
|
self.expression(args[1])
|
||||||
|
self.patchJump(jump)
|
||||||
|
of "GenericLogicalAnd":
|
||||||
|
self.expression(args[0])
|
||||||
|
var jump: int
|
||||||
|
if self.enableOptimizations:
|
||||||
|
jump = self.emitJump(JumpIfFalseOrPop)
|
||||||
|
else:
|
||||||
|
jump = self.emitJump(JumpIfFalse)
|
||||||
|
self.emitByte(Pop)
|
||||||
|
self.expression(args[1])
|
||||||
|
self.patchJump(jump)
|
||||||
else:
|
else:
|
||||||
discard # Unreachable
|
discard # Unreachable
|
||||||
|
|
||||||
|
@ -930,7 +949,6 @@ proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
proc generateObjCall(self: Compiler, args: seq[Expression]) =
|
proc generateObjCall(self: Compiler, args: seq[Expression]) =
|
||||||
## Small wrapper that abstracts emitting a call instruction
|
## Small wrapper that abstracts emitting a call instruction
|
||||||
## for a given function already loaded on the operand stack
|
## for a given function already loaded on the operand stack
|
||||||
|
|
||||||
self.emitByte(PushC) # Pops the function off the operand stack onto the call stack
|
self.emitByte(PushC) # Pops the function off the operand stack onto the call stack
|
||||||
self.emitByte(LoadReturnAddress)
|
self.emitByte(LoadReturnAddress)
|
||||||
let pos = self.chunk.code.len()
|
let pos = self.chunk.code.len()
|
||||||
|
@ -976,30 +994,6 @@ proc binary(self: Compiler, node: BinaryExpr) =
|
||||||
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", typeOfA), ("", typeOfB)]))
|
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", typeOfA), ("", typeOfB)]))
|
||||||
self.callBinaryOp(funct, node)
|
self.callBinaryOp(funct, node)
|
||||||
|
|
||||||
# TODO: Get rid of old code
|
|
||||||
#[
|
|
||||||
case node.operator.kind:
|
|
||||||
of NoMatch:
|
|
||||||
# a and b
|
|
||||||
self.expression(node.a)
|
|
||||||
var jump: int
|
|
||||||
if self.enableOptimizations:
|
|
||||||
jump = self.emitJump(JumpIfFalseOrPop)
|
|
||||||
else:
|
|
||||||
jump = self.emitJump(JumpIfFalse)
|
|
||||||
self.emitByte(Pop)
|
|
||||||
self.expression(node.b)
|
|
||||||
self.patchJump(jump)
|
|
||||||
of EndOfFile:
|
|
||||||
# a or b
|
|
||||||
self.expression(node.a)
|
|
||||||
let jump = self.emitJump(JumpIfTrue)
|
|
||||||
self.expression(node.b)
|
|
||||||
self.patchJump(jump)
|
|
||||||
else:
|
|
||||||
self.error(&"invalid AST node of kind {node.kind} at binary(): {node} (This is an internal error and most likely a bug!)")
|
|
||||||
]#
|
|
||||||
|
|
||||||
|
|
||||||
proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
||||||
## Statically declares a name into the current scope.
|
## Statically declares a name into the current scope.
|
||||||
|
@ -1007,7 +1001,7 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
||||||
## list of identifiers so that further calls to resolve()
|
## list of identifiers so that further calls to resolve()
|
||||||
## correctly return them. There is no code to actually
|
## correctly return them. There is no code to actually
|
||||||
## declare a variable at runtime: the value is already
|
## declare a variable at runtime: the value is already
|
||||||
## there on the stack
|
## on the stack
|
||||||
case node.kind:
|
case node.kind:
|
||||||
of NodeKind.varDecl:
|
of NodeKind.varDecl:
|
||||||
var node = VarDecl(node)
|
var node = VarDecl(node)
|
||||||
|
@ -1542,9 +1536,11 @@ proc importStmt(self: Compiler, node: ImportStmt) =
|
||||||
## Imports a module at compile time
|
## Imports a module at compile time
|
||||||
if self.scopeDepth > 0:
|
if self.scopeDepth > 0:
|
||||||
self.error("import statements are only allowed at the top level")
|
self.error("import statements are only allowed at the top level")
|
||||||
|
var lexer = newLexer()
|
||||||
|
var parser = newParser()
|
||||||
var compiler = newCompiler()
|
var compiler = newCompiler()
|
||||||
# TODO: Find module
|
# TODO: Find module
|
||||||
var result = compiler.compile(newParser().parse(newLexer().lex("", node.moduleName.name.lexeme), node.moduleName.name.lexeme), node.moduleName.name.lexeme)
|
var result = compiler.compile(parser.parse(lexer.lex("", node.moduleName.name.lexeme), node.moduleName.name.lexeme), node.moduleName.name.lexeme)
|
||||||
|
|
||||||
|
|
||||||
proc statement(self: Compiler, node: Statement) =
|
proc statement(self: Compiler, node: Statement) =
|
||||||
|
|
|
@ -403,29 +403,14 @@ proc call(self: Parser): Expression =
|
||||||
result = self.makeCall(result)
|
result = self.makeCall(result)
|
||||||
elif self.match(Dot):
|
elif self.match(Dot):
|
||||||
self.expect(Identifier, "expecting attribute name after '.'")
|
self.expect(Identifier, "expecting attribute name after '.'")
|
||||||
result = newGetItemExpr(result, newIdentExpr(self.peek(-1)),
|
result = newGetItemExpr(result, newIdentExpr(self.peek(-1)), self.peek(-1))
|
||||||
self.peek(-1))
|
|
||||||
elif self.match(LeftBracket):
|
|
||||||
# Slicing such as a[1:2], which is then
|
|
||||||
# translated to `[]`(a, 1, 2)
|
|
||||||
let tok = self.peek(-1)
|
|
||||||
var ends: seq[Expression] = @[]
|
|
||||||
while not self.check(RightBracket) and not self.done():
|
|
||||||
if self.check(":"):
|
|
||||||
ends.add(newNilExpr(Token(lexeme: "nil")))
|
|
||||||
discard self.step()
|
|
||||||
else:
|
|
||||||
ends.add(self.expression())
|
|
||||||
discard self.match(":")
|
|
||||||
self.expect(RightBracket, "expecting ']'")
|
|
||||||
result = newSliceExpr(result, ends, tok)
|
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
## Operator parsing handlers
|
## Operator parsing handlers
|
||||||
|
|
||||||
proc unary(self: Parser): Expression =
|
proc unary(self: Parser): Expression =
|
||||||
if self.peek().lexeme in self.operators.tokens:
|
if self.peek().kind == Symbol and self.peek().lexeme in self.operators.tokens:
|
||||||
result = newUnaryExpr(self.step(), self.unary())
|
result = newUnaryExpr(self.step(), self.unary())
|
||||||
else:
|
else:
|
||||||
result = self.call()
|
result = self.call()
|
||||||
|
@ -435,7 +420,7 @@ proc parsePow(self: Parser): Expression =
|
||||||
result = self.unary()
|
result = self.unary()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Power:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Power:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.unary()
|
right = self.unary()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -445,7 +430,7 @@ proc parseMul(self: Parser): Expression =
|
||||||
result = self.parsePow()
|
result = self.parsePow()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Multiplication:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Multiplication:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parsePow()
|
right = self.parsePow()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -455,7 +440,7 @@ proc parseAdd(self: Parser): Expression =
|
||||||
result = self.parseMul()
|
result = self.parseMul()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Addition:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Addition:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseMul()
|
right = self.parseMul()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -465,7 +450,7 @@ proc parseCmp(self: Parser): Expression =
|
||||||
result = self.parseAdd()
|
result = self.parseAdd()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Compare:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Compare:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseAdd()
|
right = self.parseAdd()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -475,7 +460,7 @@ proc parseAnd(self: Parser): Expression =
|
||||||
result = self.parseCmp()
|
result = self.parseCmp()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Precedence.And:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.And:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseCmp()
|
right = self.parseCmp()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -485,7 +470,7 @@ proc parseOr(self: Parser): Expression =
|
||||||
result = self.parseAnd()
|
result = self.parseAnd()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseAnd()
|
right = self.parseAnd()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -493,7 +478,7 @@ proc parseOr(self: Parser): Expression =
|
||||||
|
|
||||||
proc parseAssign(self: Parser): Expression =
|
proc parseAssign(self: Parser): Expression =
|
||||||
result = self.parseOr()
|
result = self.parseOr()
|
||||||
if self.operators.getPrecedence(self.peek().lexeme) == Assign:
|
if self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Assign:
|
||||||
let tok = self.step()
|
let tok = self.step()
|
||||||
var value = self.expression()
|
var value = self.expression()
|
||||||
case result.kind:
|
case result.kind:
|
||||||
|
@ -509,7 +494,7 @@ proc parseArrow(self: Parser): Expression =
|
||||||
result = self.parseAssign()
|
result = self.parseAssign()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseAssign()
|
right = self.parseAssign()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
|
Loading…
Reference in New Issue