Initial experimental support for parsing pragmas
This commit is contained in:
parent
aed0f6e8f2
commit
dac0cca1bc
|
@ -16,7 +16,8 @@ import meta/ast
|
||||||
import meta/errors
|
import meta/errors
|
||||||
import ../config
|
import ../config
|
||||||
import ../util/multibyte
|
import ../util/multibyte
|
||||||
|
import lexer
|
||||||
|
import parser
|
||||||
|
|
||||||
import strformat
|
import strformat
|
||||||
import algorithm
|
import algorithm
|
||||||
|
@ -180,6 +181,7 @@ proc newCompiler*(enableOptimizations: bool = true, replMode: bool = false): Com
|
||||||
|
|
||||||
|
|
||||||
## Forward declarations
|
## Forward declarations
|
||||||
|
proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk
|
||||||
proc expression(self: Compiler, node: Expression)
|
proc expression(self: Compiler, node: Expression)
|
||||||
proc statement(self: Compiler, node: Statement)
|
proc statement(self: Compiler, node: Statement)
|
||||||
proc declaration(self: Compiler, node: Declaration)
|
proc declaration(self: Compiler, node: Declaration)
|
||||||
|
@ -779,8 +781,12 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
|
||||||
msg &= &", wrong number of arguments ({name.valueType.args.len()} expected, got {kind.args.len()})"
|
msg &= &", wrong number of arguments ({name.valueType.args.len()} expected, got {kind.args.len()})"
|
||||||
else:
|
else:
|
||||||
for i, arg in kind.args:
|
for i, arg in kind.args:
|
||||||
if not self.compareTypes(arg.kind, name.valueType.args[i].kind):
|
if name.valueType.args[i].kind.kind == Mutable and arg.kind.kind != Mutable:
|
||||||
|
msg &= &", first mismatch at position {i + 1}: {name.valueType.args[i].name} is immutable, not 'var'"
|
||||||
|
break
|
||||||
|
elif not self.compareTypes(arg.kind, name.valueType.args[i].kind):
|
||||||
msg &= &", first mismatch at position {i + 1}: expected argument of type '{self.typeToStr(name.valueType.args[i].kind)}', got '{self.typeToStr(arg.kind)}' instead"
|
msg &= &", first mismatch at position {i + 1}: expected argument of type '{self.typeToStr(name.valueType.args[i].kind)}', got '{self.typeToStr(arg.kind)}' instead"
|
||||||
|
break
|
||||||
self.error(msg)
|
self.error(msg)
|
||||||
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"
|
||||||
|
@ -869,7 +875,7 @@ proc binary(self: Compiler, node: BinaryExpr) =
|
||||||
]#
|
]#
|
||||||
|
|
||||||
|
|
||||||
proc declareName(self: Compiler, node: Declaration) =
|
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.
|
||||||
## "Declaring" a name only means updating our internal
|
## "Declaring" a name only means updating our internal
|
||||||
## list of identifiers so that further calls to resolve()
|
## list of identifiers so that further calls to resolve()
|
||||||
|
@ -900,6 +906,8 @@ proc declareName(self: Compiler, node: Declaration) =
|
||||||
isLet: node.isLet,
|
isLet: node.isLet,
|
||||||
isClosedOver: false,
|
isClosedOver: false,
|
||||||
line: node.token.line))
|
line: node.token.line))
|
||||||
|
if mutable:
|
||||||
|
self.names[^1].valueType = Type(kind: Mutable, value: self.names[^1].valueType)
|
||||||
# We emit a jump of 0 because this may become a
|
# We emit a jump of 0 because this may become a
|
||||||
# StoreHeap instruction. If they variable is
|
# StoreHeap instruction. If they variable is
|
||||||
# not closed over, we'll sadly be wasting a
|
# not closed over, we'll sadly be wasting a
|
||||||
|
@ -932,6 +940,10 @@ proc declareName(self: Compiler, node: Declaration) =
|
||||||
isClosedOver: false,
|
isClosedOver: false,
|
||||||
line: node.token.line))
|
line: node.token.line))
|
||||||
let fn = self.names[^1]
|
let fn = self.names[^1]
|
||||||
|
if fn.valueType.returnType.isNil() and not node.returnType.isNil() and node.returnType.kind == identExpr:
|
||||||
|
for g in node.generics:
|
||||||
|
if g.name == IdentExpr(node.returnType):
|
||||||
|
fn.valueType.returnType = Type(kind: Generic)
|
||||||
var name: Name
|
var name: Name
|
||||||
for argument in node.arguments:
|
for argument in node.arguments:
|
||||||
if self.names.high() > 16777215:
|
if self.names.high() > 16777215:
|
||||||
|
@ -1185,12 +1197,14 @@ proc expression(self: Compiler, node: Expression) =
|
||||||
of NodeKind.callExpr:
|
of NodeKind.callExpr:
|
||||||
self.callExpr(CallExpr(node)) # TODO
|
self.callExpr(CallExpr(node)) # TODO
|
||||||
of getItemExpr:
|
of getItemExpr:
|
||||||
|
discard # TODO: Get rid of this
|
||||||
|
of pragmaExpr:
|
||||||
discard # TODO
|
discard # TODO
|
||||||
# Note that for setItem and assign we don't convert
|
# Note that for setItem and assign we don't convert
|
||||||
# the node to its true type because that type information
|
# the node to its true type because that type information
|
||||||
# would be lost in the call anyway. The differentiation
|
# would be lost in the call anyway. The differentiation
|
||||||
# happens in self.assignment()
|
# happens in self.assignment()
|
||||||
of setItemExpr, assignExpr:
|
of setItemExpr, assignExpr: # TODO: Get rid of this
|
||||||
self.assignment(node)
|
self.assignment(node)
|
||||||
of identExpr:
|
of identExpr:
|
||||||
self.identifier(IdentExpr(node))
|
self.identifier(IdentExpr(node))
|
||||||
|
@ -1260,26 +1274,29 @@ proc endFunctionBeforeReturn(self: Compiler) =
|
||||||
proc returnStmt(self: Compiler, node: ReturnStmt) =
|
proc returnStmt(self: Compiler, node: ReturnStmt) =
|
||||||
## Compiles return statements. An empty return
|
## Compiles return statements. An empty return
|
||||||
## implicitly returns nil
|
## implicitly returns nil
|
||||||
let returnType = self.inferType(node.value)
|
let actual = self.inferType(node.value)
|
||||||
let typ = self.inferType(self.currentFunction)
|
let expected = self.inferType(self.currentFunction)
|
||||||
|
var comp: Type = actual
|
||||||
|
if not expected.isNil() and not expected.returnType.isNil() and expected.returnType.kind in {Reference, Pointer, Mutable}:
|
||||||
|
comp = expected.returnType.value
|
||||||
## Having the return type
|
## Having the return type
|
||||||
if returnType == nil and typ.returnType != nil:
|
if actual.isNil() and not expected.returnType.isNil():
|
||||||
if node.value != nil:
|
if not node.value.isNil():
|
||||||
if node.value.kind == identExpr:
|
if node.value.kind == identExpr:
|
||||||
self.error(&"reference to undeclared identifier '{node.value.token.lexeme}'")
|
self.error(&"reference to undeclared identifier '{node.value.token.lexeme}'")
|
||||||
elif node.value.kind == callExpr and CallExpr(node.value).callee.kind == identExpr:
|
elif node.value.kind == callExpr and CallExpr(node.value).callee.kind == identExpr:
|
||||||
self.error(&"call to undeclared function '{CallExpr(node.value).callee.token.lexeme}'")
|
self.error(&"call to undeclared function '{CallExpr(node.value).callee.token.lexeme}'")
|
||||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', but expression has no type")
|
self.error(&"expected return value of type '{self.typeToStr(expected.returnType)}', but expression has no type")
|
||||||
elif typ.returnType == nil and returnType != nil:
|
elif expected.returnType.isNil() and not actual.isNil():
|
||||||
self.error("non-empty return statement is not allowed in void functions")
|
self.error("non-empty return statement is not allowed in void functions")
|
||||||
elif not self.compareTypes(returnType, typ.returnType):
|
elif not self.compareTypes(actual, comp):
|
||||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', got '{self.typeToStr(returnType)}' instead")
|
self.error(&"expected return value of type '{self.typeToStr(comp)}', got '{self.typeToStr(actual)}' instead")
|
||||||
if node.value != nil:
|
if not node.value.isNil():
|
||||||
self.expression(node.value)
|
self.expression(node.value)
|
||||||
self.emitByte(OpCode.SetResult)
|
self.emitByte(OpCode.SetResult)
|
||||||
self.endFunctionBeforeReturn()
|
self.endFunctionBeforeReturn()
|
||||||
self.emitByte(OpCode.Return)
|
self.emitByte(OpCode.Return)
|
||||||
if node.value != nil:
|
if not node.value.isNil():
|
||||||
self.emitByte(1)
|
self.emitByte(1)
|
||||||
else:
|
else:
|
||||||
self.emitByte(0)
|
self.emitByte(0)
|
||||||
|
@ -1292,7 +1309,7 @@ proc yieldStmt(self: Compiler, node: YieldStmt) =
|
||||||
|
|
||||||
|
|
||||||
proc raiseStmt(self: Compiler, node: RaiseStmt) =
|
proc raiseStmt(self: Compiler, node: RaiseStmt) =
|
||||||
## Compiles yield statements
|
## Compiles raise statements
|
||||||
self.expression(node.exception)
|
self.expression(node.exception)
|
||||||
self.emitByte(OpCode.Raise)
|
self.emitByte(OpCode.Raise)
|
||||||
|
|
||||||
|
@ -1336,6 +1353,20 @@ proc assertStmt(self: Compiler, node: AssertStmt) =
|
||||||
self.emitByte(OpCode.Assert)
|
self.emitByte(OpCode.Assert)
|
||||||
|
|
||||||
|
|
||||||
|
proc forEachStmt(self: Compiler, node: ForEachStmt) =
|
||||||
|
## Compiles foreach loops
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
|
||||||
|
proc importStmt(self: Compiler, node: ImportStmt) =
|
||||||
|
## Imports a module at compile time
|
||||||
|
if self.scopeDepth > 0:
|
||||||
|
self.error("import statements are only allowed at the top level")
|
||||||
|
var compiler = newCompiler()
|
||||||
|
# TODO: Find module
|
||||||
|
var result = compiler.compile(newParser().parse(newLexer().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) =
|
||||||
## Compiles all statements
|
## Compiles all statements
|
||||||
case node.kind:
|
case node.kind:
|
||||||
|
@ -1365,7 +1396,7 @@ proc statement(self: Compiler, node: Statement) =
|
||||||
of NodeKind.returnStmt:
|
of NodeKind.returnStmt:
|
||||||
self.returnStmt(ReturnStmt(node))
|
self.returnStmt(ReturnStmt(node))
|
||||||
of NodeKind.importStmt:
|
of NodeKind.importStmt:
|
||||||
discard
|
self.importStmt(ImportStmt(node))
|
||||||
of NodeKind.whileStmt, NodeKind.forStmt:
|
of NodeKind.whileStmt, NodeKind.forStmt:
|
||||||
## Our parser already desugars for loops to
|
## Our parser already desugars for loops to
|
||||||
## while loops!
|
## while loops!
|
||||||
|
@ -1376,7 +1407,7 @@ proc statement(self: Compiler, node: Statement) =
|
||||||
self.patchBreaks()
|
self.patchBreaks()
|
||||||
self.currentLoop = loop
|
self.currentLoop = loop
|
||||||
of NodeKind.forEachStmt:
|
of NodeKind.forEachStmt:
|
||||||
discard
|
self.forEachStmt(ForEachStmt(node))
|
||||||
of NodeKind.blockStmt:
|
of NodeKind.blockStmt:
|
||||||
self.blockStmt(BlockStmt(node))
|
self.blockStmt(BlockStmt(node))
|
||||||
of NodeKind.yieldStmt:
|
of NodeKind.yieldStmt:
|
||||||
|
@ -1405,11 +1436,16 @@ proc varDecl(self: Compiler, node: VarDecl) =
|
||||||
if expected != nil:
|
if expected != nil:
|
||||||
self.error(&"expected value of type '{self.typeToStr(expected)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(actual)}'")
|
self.error(&"expected value of type '{self.typeToStr(expected)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(actual)}'")
|
||||||
self.expression(node.value)
|
self.expression(node.value)
|
||||||
self.declareName(node)
|
self.declareName(node, mutable=node.token.kind == Var)
|
||||||
self.emitByte(StoreVar)
|
self.emitByte(StoreVar)
|
||||||
self.emitBytes(self.names.high().toTriple())
|
self.emitBytes(self.names.high().toTriple())
|
||||||
|
|
||||||
|
|
||||||
|
proc typeDecl(self: Compiler, node: TypeDecl) =
|
||||||
|
## Compiles type declarations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc funDecl(self: Compiler, node: FunDecl) =
|
proc funDecl(self: Compiler, node: FunDecl) =
|
||||||
## Compiles function declarations
|
## Compiles function declarations
|
||||||
# A function's code is just compiled linearly
|
# A function's code is just compiled linearly
|
||||||
|
@ -1422,8 +1458,16 @@ proc funDecl(self: Compiler, node: FunDecl) =
|
||||||
let jmp = self.emitJump(JumpForwards)
|
let jmp = self.emitJump(JumpForwards)
|
||||||
for argument in node.arguments:
|
for argument in node.arguments:
|
||||||
self.emitByte(LoadArgument)
|
self.emitByte(LoadArgument)
|
||||||
if node.returnType != nil and self.inferType(node.returnType) == nil:
|
if not node.returnType.isNil() and self.inferType(node.returnType).isNil():
|
||||||
self.error(&"cannot infer the type of '{node.returnType.token.lexeme}'")
|
var isGeneric = false
|
||||||
|
if node.returnType.kind == identExpr:
|
||||||
|
let name = IdentExpr(node.returnType)
|
||||||
|
for g in node.generics:
|
||||||
|
if name == g.name:
|
||||||
|
isGeneric = true
|
||||||
|
break
|
||||||
|
if not isGeneric:
|
||||||
|
self.error(&"cannot infer the type of '{node.returnType.token.lexeme}'")
|
||||||
# TODO: Forward declarations
|
# TODO: Forward declarations
|
||||||
if node.body != nil:
|
if node.body != nil:
|
||||||
if BlockStmt(node.body).code.len() == 0:
|
if BlockStmt(node.body).code.len() == 0:
|
||||||
|
@ -1512,7 +1556,6 @@ proc patchReturnAddress(self: Compiler, pos: int) =
|
||||||
self.chunk.code[pos + 3] = address[3]
|
self.chunk.code[pos + 3] = address[3]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc declaration(self: Compiler, node: Declaration) =
|
proc declaration(self: Compiler, node: Declaration) =
|
||||||
## Compiles all declarations
|
## Compiles all declarations
|
||||||
case node.kind:
|
case node.kind:
|
||||||
|
@ -1520,6 +1563,8 @@ proc declaration(self: Compiler, node: Declaration) =
|
||||||
self.varDecl(VarDecl(node))
|
self.varDecl(VarDecl(node))
|
||||||
of NodeKind.funDecl:
|
of NodeKind.funDecl:
|
||||||
self.funDecl(FunDecl(node))
|
self.funDecl(FunDecl(node))
|
||||||
|
of NodeKind.typeDecl:
|
||||||
|
self.typeDecl(TypeDecl(node))
|
||||||
else:
|
else:
|
||||||
self.statement(Statement(node))
|
self.statement(Statement(node))
|
||||||
|
|
||||||
|
|
|
@ -594,10 +594,13 @@ proc next(self: Lexer) =
|
||||||
# Keywords and identifiers
|
# Keywords and identifiers
|
||||||
self.parseIdentifier()
|
self.parseIdentifier()
|
||||||
elif self.match("#"):
|
elif self.match("#"):
|
||||||
# Inline comments, pragmas, etc.
|
if not self.match("pragma["):
|
||||||
while not (self.check("\n") or self.done()):
|
# Inline comments
|
||||||
discard self.step()
|
while not (self.check("\n") or self.done()):
|
||||||
self.createToken(Comment)
|
discard self.step()
|
||||||
|
self.createToken(Comment)
|
||||||
|
else:
|
||||||
|
self.createToken(Pragma)
|
||||||
else:
|
else:
|
||||||
# If none of the above conditions matched, there's a few
|
# If none of the above conditions matched, there's a few
|
||||||
# other options left:
|
# other options left:
|
||||||
|
@ -607,7 +610,7 @@ proc next(self: Lexer) =
|
||||||
# We handle all of these cases here by trying to
|
# We handle all of these cases here by trying to
|
||||||
# match the longest sequence of characters possible
|
# match the longest sequence of characters possible
|
||||||
# as either an operator or a statement/expression
|
# as either an operator or a statement/expression
|
||||||
# delimiter, erroring out if there's no match
|
# delimiter
|
||||||
var n = self.symbols.getMaxSymbolSize()
|
var n = self.symbols.getMaxSymbolSize()
|
||||||
while n > 0:
|
while n > 0:
|
||||||
for symbol in self.symbols.getSymbols(n):
|
for symbol in self.symbols.getSymbols(n):
|
||||||
|
|
|
@ -265,8 +265,9 @@ type
|
||||||
TypeDecl* = ref object of Declaration
|
TypeDecl* = ref object of Declaration
|
||||||
name*: IdentExpr
|
name*: IdentExpr
|
||||||
fields*: seq[tuple[name: IdentExpr, valueType: Expression,
|
fields*: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||||
mutable: bool, isRef: bool, isPtr: bool]]
|
mutable: bool, isRef: bool, isPtr: bool, isPrivate: bool]]
|
||||||
defaults*: seq[Expression]
|
defaults*: seq[Expression]
|
||||||
|
isRef*: bool
|
||||||
|
|
||||||
Pragma* = ref object of Expression
|
Pragma* = ref object of Expression
|
||||||
name*: IdentExpr
|
name*: IdentExpr
|
||||||
|
@ -307,6 +308,7 @@ proc newPragma*(name: IdentExpr, args: seq[LiteralExpr]): Pragma =
|
||||||
result.kind = pragmaExpr
|
result.kind = pragmaExpr
|
||||||
result.args = args
|
result.args = args
|
||||||
result.name = name
|
result.name = name
|
||||||
|
result.token = name.token
|
||||||
|
|
||||||
|
|
||||||
proc newIntExpr*(literal: Token): IntExpr =
|
proc newIntExpr*(literal: Token): IntExpr =
|
||||||
|
@ -596,9 +598,9 @@ proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueTyp
|
||||||
result.generics = generics
|
result.generics = generics
|
||||||
|
|
||||||
|
|
||||||
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool]],
|
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool, isPrivate: bool]],
|
||||||
defaults: seq[Expression], isPrivate: bool, token: Token, pragmas: seq[Pragma],
|
defaults: seq[Expression], isPrivate: bool, token: Token, pragmas: seq[Pragma],
|
||||||
generics: seq[tuple[name: IdentExpr, cond: Expression]]): TypeDecl =
|
generics: seq[tuple[name: IdentExpr, cond: Expression]], isRef: bool): TypeDecl =
|
||||||
result = TypeDecl(kind: typeDecl)
|
result = TypeDecl(kind: typeDecl)
|
||||||
result.name = name
|
result.name = name
|
||||||
result.fields = fields
|
result.fields = fields
|
||||||
|
@ -607,6 +609,7 @@ proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType:
|
||||||
result.token = token
|
result.token = token
|
||||||
result.pragmas = pragmas
|
result.pragmas = pragmas
|
||||||
result.generics = generics
|
result.generics = generics
|
||||||
|
result.isRef = isRef
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -690,10 +693,13 @@ proc `$`*(self: ASTNode): string =
|
||||||
result &= &"AwaitStmt({self.expression})"
|
result &= &"AwaitStmt({self.expression})"
|
||||||
of varDecl:
|
of varDecl:
|
||||||
var self = VarDecl(self)
|
var self = VarDecl(self)
|
||||||
result &= &"Var(name={self.name}, value={self.value}, const={self.isConst}, private={self.isPrivate}, type={self.valueType})"
|
result &= &"Var(name={self.name}, value={self.value}, const={self.isConst}, private={self.isPrivate}, type={self.valueType}, pragmas={self.pragmas})"
|
||||||
of funDecl:
|
of funDecl:
|
||||||
var self = FunDecl(self)
|
var self = FunDecl(self)
|
||||||
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generics=[{self.generics.join(", ")}], async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate})"""
|
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generics=[{self.generics.join(", ")}], async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate})"""
|
||||||
|
of typeDecl:
|
||||||
|
var self = TypeDecl(self)
|
||||||
|
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, defaults={self.defaults}, private={self.isPrivate}, pragmas={self.pragmas}, generics={self.generics}, ref={self.isRef})"""
|
||||||
of lambdaExpr:
|
of lambdaExpr:
|
||||||
var self = LambdaExpr(self)
|
var self = LambdaExpr(self)
|
||||||
result &= &"""Lambda(body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generator={self.isGenerator}, async={self.isAsync})"""
|
result &= &"""Lambda(body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generator={self.isGenerator}, async={self.isAsync})"""
|
||||||
|
@ -715,6 +721,9 @@ proc `$`*(self: ASTNode): string =
|
||||||
else:
|
else:
|
||||||
result &= ", elseClause=nil"
|
result &= ", elseClause=nil"
|
||||||
result &= ")"
|
result &= ")"
|
||||||
|
of pragmaExpr:
|
||||||
|
var self = Pragma(self)
|
||||||
|
result &= &"Pragma(name={self.name}, args={self.args})"
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ type
|
||||||
Raise, Assert, Await, Foreach,
|
Raise, Assert, Await, Foreach,
|
||||||
Yield, Defer, Try, Except,
|
Yield, Defer, Try, Except,
|
||||||
Finally, Type, Operator, Case,
|
Finally, Type, Operator, Case,
|
||||||
Enum, From, Ptr, Ref
|
Enum, From, Ptr, Ref, Object
|
||||||
|
|
||||||
# Literal types
|
# Literal types
|
||||||
Integer, Float, String, Identifier,
|
Integer, Float, String, Identifier,
|
||||||
|
@ -59,6 +59,7 @@ type
|
||||||
NoMatch, # Used internally by the symbol table
|
NoMatch, # Used internally by the symbol table
|
||||||
Comment, # Useful for documentation comments, pragmas, etc.
|
Comment, # Useful for documentation comments, pragmas, etc.
|
||||||
Symbol, # A generic symbol
|
Symbol, # A generic symbol
|
||||||
|
Pragma,
|
||||||
# These are not used at the moment but may be
|
# These are not used at the moment but may be
|
||||||
# employed to enforce indentation or other neat
|
# employed to enforce indentation or other neat
|
||||||
# stuff I haven't thought about yet
|
# stuff I haven't thought about yet
|
||||||
|
@ -66,6 +67,7 @@ type
|
||||||
Tab,
|
Tab,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Token* = ref object
|
Token* = ref object
|
||||||
## A token object
|
## A token object
|
||||||
kind*: TokenType # Type of the token
|
kind*: TokenType # Type of the token
|
||||||
|
|
|
@ -377,13 +377,12 @@ proc makeCall(self: Parser, callee: Expression): Expression =
|
||||||
self.error("call can not have more than 255 arguments")
|
self.error("call can not have more than 255 arguments")
|
||||||
break
|
break
|
||||||
argument = self.expression()
|
argument = self.expression()
|
||||||
if argument.kind == assignExpr:
|
if argument.kind == binaryExpr and BinaryExpr(argument).operator.lexeme == "=":
|
||||||
# TODO: This will explode with slices!
|
# TODO: This will explode with slices!
|
||||||
if IdentExpr(AssignExpr(argument).name) in argNames:
|
if IdentExpr(BinaryExpr(argument).a) in argNames:
|
||||||
self.error("duplicate keyword argument in call")
|
self.error("duplicate keyword argument in call")
|
||||||
argNames.add(IdentExpr(AssignExpr(argument).name))
|
argNames.add(IdentExpr(BinaryExpr(argument).a))
|
||||||
arguments.keyword.add((name: IdentExpr(AssignExpr(
|
arguments.keyword.add((name: IdentExpr(BinaryExpr(argument).a), value: BinaryExpr(argument).b))
|
||||||
argument).name), value: AssignExpr(argument).value))
|
|
||||||
elif arguments.keyword.len() == 0:
|
elif arguments.keyword.len() == 0:
|
||||||
arguments.positionals.add(argument)
|
arguments.positionals.add(argument)
|
||||||
else:
|
else:
|
||||||
|
@ -1077,27 +1076,110 @@ proc statement(self: Parser): Statement =
|
||||||
result = self.expressionStatement()
|
result = self.expressionStatement()
|
||||||
|
|
||||||
|
|
||||||
proc parsePragma(self: Parser): Pragma =
|
proc parsePragma(self: Parser): tuple[global: bool, pragmas: seq[Pragma]] =
|
||||||
## Parses pragmas
|
## Parses pragmas
|
||||||
if self.scopeDepth == 0:
|
result.global = true
|
||||||
## Pragmas used at the
|
var
|
||||||
## top level are either
|
decl: Declaration = nil
|
||||||
## used for compile-time
|
found = false
|
||||||
## switches or for global variable
|
for node in self.tree:
|
||||||
## declarations
|
if node.token.line == self.peek(-1).line and node.kind in {NodeKind.varDecl, typeDecl, funDecl, lambdaExpr}:
|
||||||
var decl: VarDecl
|
decl = node
|
||||||
for node in self.tree:
|
found = true
|
||||||
if node.token.line == self.peek(-1).line and node.kind == varDecl:
|
break
|
||||||
decl = VarDecl(node)
|
if not found:
|
||||||
|
# Dummy declaration
|
||||||
|
result.global = false
|
||||||
|
decl = Declaration(pragmas: @[])
|
||||||
|
var
|
||||||
|
name: IdentExpr
|
||||||
|
args: seq[LiteralExpr]
|
||||||
|
exp: Expression
|
||||||
|
while not self.match("]") and not self.done():
|
||||||
|
args = @[]
|
||||||
|
self.expect(Identifier, "expecting pragma name")
|
||||||
|
name = newIdentExpr(self.peek(-1))
|
||||||
|
if not self.match(":"):
|
||||||
|
if self.match("]"):
|
||||||
|
decl.pragmas.add(newPragma(name, @[]))
|
||||||
break
|
break
|
||||||
else:
|
elif self.match("("):
|
||||||
var decl = self.currentFunction
|
while not self.match(")") and not self.done():
|
||||||
# TODO
|
exp = self.primary()
|
||||||
|
if not exp.isLiteral():
|
||||||
|
self.error("invalid syntax")
|
||||||
|
args.add(LiteralExpr(exp))
|
||||||
|
if not self.match(","):
|
||||||
|
break
|
||||||
|
self.expect(")", "unterminated parenthesis in pragma arguments")
|
||||||
|
else:
|
||||||
|
exp = self.primary()
|
||||||
|
if not exp.isLiteral():
|
||||||
|
self.error("invalid syntax")
|
||||||
|
args.add(LiteralExpr(exp))
|
||||||
|
if self.match(","):
|
||||||
|
continue
|
||||||
|
decl.pragmas.add(newPragma(name, args))
|
||||||
|
result.pragmas = decl.pragmas
|
||||||
|
|
||||||
|
|
||||||
proc typeDecl(self: Parser): TypeDecl =
|
proc typeDecl(self: Parser): TypeDecl =
|
||||||
## Parses type declarations
|
## Parses type declarations
|
||||||
|
let token = self.peek(-1)
|
||||||
|
self.expect(Identifier, "expecting type name after 'type'")
|
||||||
|
let isPrivate = not self.match("*")
|
||||||
|
self.checkDecl(isPrivate)
|
||||||
|
var name = newIdentExpr(self.peek(-1))
|
||||||
|
var isRef = false
|
||||||
|
var fields: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||||
|
mutable: bool, isRef: bool, isPtr: bool, isPrivate: bool]] = @[]
|
||||||
|
var defaults: seq[Expression] = @[]
|
||||||
|
var generics: seq[tuple[name: IdentExpr, cond: Expression]] = @[]
|
||||||
|
var pragmas: seq[Pragma] = @[]
|
||||||
|
result = newTypeDecl(name, fields, defaults, isPrivate, token, pragmas, generics, isRef)
|
||||||
|
if self.match(LeftBracket):
|
||||||
|
self.parseGenerics(result)
|
||||||
|
self.expect("=", "expecting '=' after type name")
|
||||||
|
case self.step().kind:
|
||||||
|
of Ref:
|
||||||
|
isRef = true
|
||||||
|
echo self.peek()
|
||||||
|
self.expect(Object, "invalid syntax")
|
||||||
|
of Object:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
self.error("invalid syntax")
|
||||||
|
self.expect(LeftBrace, "expecting '{' after type declaration")
|
||||||
|
var
|
||||||
|
argName: IdentExpr
|
||||||
|
argMutable: bool
|
||||||
|
argRef: bool
|
||||||
|
argPtr: bool
|
||||||
|
argPrivate: bool
|
||||||
|
argType: Expression
|
||||||
|
while not self.match(RightBrace) and not self.done():
|
||||||
|
argRef = false
|
||||||
|
argPtr = false
|
||||||
|
argMutable = false
|
||||||
|
self.expect(Identifier, "expecting field name")
|
||||||
|
argName = newIdentExpr(self.peek(-1))
|
||||||
|
argPrivate = not self.match("*")
|
||||||
|
self.expect(":", "expecting ':' after field name")
|
||||||
|
case self.step().kind:
|
||||||
|
of Ref:
|
||||||
|
argRef = true
|
||||||
|
of Ptr:
|
||||||
|
argPtr = true
|
||||||
|
of Var:
|
||||||
|
argMutable = true
|
||||||
|
else:
|
||||||
|
self.current -= 1
|
||||||
|
argType = self.expression()
|
||||||
|
result.fields.add((argName, argType, argMutable, argRef, argPtr, argPrivate))
|
||||||
|
if self.match("="):
|
||||||
|
result.defaults.add(self.expression())
|
||||||
|
self.expect(";", "expecting semicolon after field declaration")
|
||||||
|
|
||||||
|
|
||||||
proc declaration(self: Parser): Declaration =
|
proc declaration(self: Parser): Declaration =
|
||||||
## Parses declarations
|
## Parses declarations
|
||||||
|
@ -1118,10 +1200,13 @@ proc declaration(self: Parser): Declaration =
|
||||||
of Operator:
|
of Operator:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.funDecl(isOperator=true)
|
result = self.funDecl(isOperator=true)
|
||||||
of TokenType.Comment:
|
of TokenType.Pragma:
|
||||||
let tok = self.step()
|
discard self.step()
|
||||||
if tok.lexeme.startsWith("#pragma["):
|
let temp = self.parsePragma()
|
||||||
result = self.parsePragma()
|
if not temp.global:
|
||||||
|
for p in temp.pragmas:
|
||||||
|
self.tree.add(p)
|
||||||
|
result = nil
|
||||||
of Type:
|
of Type:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.typeDecl()
|
result = self.typeDecl()
|
||||||
|
|
11
src/main.nim
11
src/main.nim
|
@ -28,11 +28,11 @@ proc fillSymbolTable(tokenizer: Lexer)
|
||||||
proc getLineEditor: LineEditor
|
proc getLineEditor: LineEditor
|
||||||
|
|
||||||
# Handy dandy compile-time constants
|
# Handy dandy compile-time constants
|
||||||
const debugLexer = false
|
const debugLexer {.booldefine.} = false
|
||||||
const debugParser = false
|
const debugParser {.booldefine.} = false
|
||||||
const debugCompiler = true
|
const debugCompiler {.booldefine.} = false
|
||||||
const debugSerializer = false
|
const debugSerializer {.booldefine.} = false
|
||||||
const debugRuntime = false
|
const debugRuntime {.booldefine.} = false
|
||||||
|
|
||||||
|
|
||||||
proc repl(vm: PeonVM = newPeonVM()) =
|
proc repl(vm: PeonVM = newPeonVM()) =
|
||||||
|
@ -402,6 +402,7 @@ proc fillSymbolTable(tokenizer: Lexer) =
|
||||||
tokenizer.symbols.addKeyword("import", Import)
|
tokenizer.symbols.addKeyword("import", Import)
|
||||||
tokenizer.symbols.addKeyword("yield", TokenType.Yield)
|
tokenizer.symbols.addKeyword("yield", TokenType.Yield)
|
||||||
tokenizer.symbols.addKeyword("return", TokenType.Return)
|
tokenizer.symbols.addKeyword("return", TokenType.Return)
|
||||||
|
tokenizer.symbols.addKeyword("object", Object)
|
||||||
# These are more like expressions with a reserved
|
# These are more like expressions with a reserved
|
||||||
# name that produce a value of a builtin type,
|
# name that produce a value of a builtin type,
|
||||||
# but we don't need to care about that until
|
# but we don't need to care about that until
|
||||||
|
|
Loading…
Reference in New Issue