Updated .gitignore, slightly edited README and added some more tests
This commit is contained in:
parent
998ba94902
commit
94ce81b6f1
|
@ -2,7 +2,6 @@
|
|||
nimcache/
|
||||
nimblecache/
|
||||
htmldocs/
|
||||
tests/*.pbc # Peon bytecode files
|
||||
peon
|
||||
*.pbc # Peon bytecode files
|
||||
bin/
|
||||
.vscode/
|
||||
|
|
23
README.md
23
README.md
|
@ -52,25 +52,26 @@ In no particular order, here's a list of stuff that's done/to do (might be incom
|
|||
|
||||
Toolchain:
|
||||
|
||||
- Tokenizer (with dynamic symbol table) -> Done
|
||||
- Parser (with support for custom operators, even builtins) -> Done
|
||||
- Tokenizer (with dynamic symbol table) [X]
|
||||
- Parser (with support for custom operators, even builtins) [X]
|
||||
- Compiler [ ] -> Being written
|
||||
- VM [ ] -> Being written
|
||||
- Bytecode (de-)serializer -> Done
|
||||
- Static code debugger [x] -> Done
|
||||
- Runtime debugger/inspection tool -> TODO
|
||||
- Bytecode (de-)serializer [X]
|
||||
- Static code debugger [X]
|
||||
- Runtime debugger/inspection tool [ ]
|
||||
|
||||
Type system:
|
||||
|
||||
- Custom types -> TODO
|
||||
- Intrinsics -> Done
|
||||
- Generics -> TODO
|
||||
- Function calls -> WIP
|
||||
- Custom types [ ]
|
||||
- Intrinsics [X]
|
||||
- Generics [ ] -> WIP
|
||||
- Functions [X]
|
||||
|
||||
Misc:
|
||||
|
||||
- Pragmas -> TODO
|
||||
- Attribute resolution -> TODO
|
||||
- Pragmas [ ] -> WIP (Some pragmas implemented)
|
||||
- Attribute resolution [ ]
|
||||
- method-like call syntax without actual methods (dispatched at compile-time) [ ]
|
||||
- ... More?
|
||||
|
||||
## The name
|
||||
|
|
|
@ -33,7 +33,7 @@ type
|
|||
of Byte:
|
||||
`byte`*: byte
|
||||
of Int8:
|
||||
tiny*: uint8
|
||||
tiny*: int8
|
||||
of UInt8:
|
||||
uTiny*: uint8
|
||||
of Int16:
|
||||
|
|
|
@ -99,20 +99,6 @@ proc peek(self: PeonVM, distance: int = 0): PeonObject =
|
|||
return self.operands[self.operands.high() + distance]
|
||||
|
||||
|
||||
proc get(self: PeonVM, idx: int): PeonObject =
|
||||
## Accessor method that abstracts
|
||||
## indexing the through stack
|
||||
## frames
|
||||
return self.operands[idx + self.frames[^1]]
|
||||
|
||||
|
||||
proc set(self: PeonVM, idx: int, val: PeonObject) =
|
||||
## Setter method that abstracts
|
||||
## indexing through stack
|
||||
## frames
|
||||
self.operands[idx + self.frames[^1]] = val
|
||||
|
||||
|
||||
proc pushc(self: PeonVM, val: PeonObject) =
|
||||
## Pushes a new object to the
|
||||
## call stack
|
||||
|
@ -257,7 +243,7 @@ proc constReadInt8(self: PeonVM, idx: int): PeonObject =
|
|||
## chunk's constant table and
|
||||
## returns a Peon object. Assumes
|
||||
## the constant is an Int8
|
||||
result = PeonObject(kind: Int8, tiny: self.chunk.consts[idx])
|
||||
result = PeonObject(kind: Int8, tiny: int8(self.chunk.consts[idx]))
|
||||
|
||||
|
||||
proc constReadUInt8(self: PeonVM, idx: int): PeonObject =
|
||||
|
@ -601,6 +587,14 @@ proc dispatch*(self: PeonVM) =
|
|||
of DivFloat32:
|
||||
let second = self.pop()
|
||||
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat / second.halfFloat))
|
||||
of NegInt64:
|
||||
self.push(PeonObject(kind: Int64, long: -self.pop().long))
|
||||
of NegInt32:
|
||||
self.push(PeonObject(kind: Int32, `int`: -self.pop().`int`))
|
||||
of NegInt16:
|
||||
self.push(PeonObject(kind: Int16, short: -self.pop().short))
|
||||
of NegInt8:
|
||||
self.push(PeonObject(kind: Int8, tiny: -self.pop().tiny))
|
||||
else:
|
||||
discard
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ type
|
|||
UInt32, Int64, UInt64, Float32, Float64,
|
||||
Char, Byte, String, Function, CustomType,
|
||||
Nil, Nan, Bool, Inf, Typevar, Generic,
|
||||
Mutable, Reference, Pointer
|
||||
Reference, Pointer
|
||||
Any # Any is used internally in a few cases,
|
||||
# for example when looking for operators
|
||||
# when only the type of the arguments is of
|
||||
|
@ -49,6 +49,7 @@ type
|
|||
Type = ref object
|
||||
## A wrapper around
|
||||
## compile-time types
|
||||
mutable: bool
|
||||
case kind: TypeKind:
|
||||
of Function:
|
||||
name: string
|
||||
|
@ -59,8 +60,10 @@ type
|
|||
returnType: Type
|
||||
isBuiltinFunction: bool
|
||||
builtinOp: string
|
||||
of Mutable, Reference, Pointer:
|
||||
of Reference, Pointer:
|
||||
value: Type
|
||||
of Generic:
|
||||
node: IdentExpr
|
||||
else:
|
||||
discard
|
||||
|
||||
|
@ -177,11 +180,11 @@ proc declaration(self: Compiler, node: Declaration)
|
|||
proc peek(self: Compiler, distance: int = 0): ASTNode
|
||||
proc identifier(self: Compiler, node: IdentExpr)
|
||||
proc varDecl(self: Compiler, node: VarDecl)
|
||||
proc inferType(self: Compiler, node: LiteralExpr): Type
|
||||
proc inferType(self: Compiler, node: Expression): Type
|
||||
proc inferType(self: Compiler, node: LiteralExpr, strictMutable: bool = true): Type
|
||||
proc inferType(self: Compiler, node: Expression, strictMutable: bool = true): Type
|
||||
proc findByName(self: Compiler, name: string): seq[Name]
|
||||
proc findByType(self: Compiler, name: string, kind: Type, strictRef: bool = true): seq[Name]
|
||||
proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool
|
||||
proc findByType(self: Compiler, name: string, kind: Type, strictMutable: bool = true): seq[Name]
|
||||
proc compareTypes(self: Compiler, a, b: Type, strictMutable: bool = true): bool
|
||||
proc patchReturnAddress(self: Compiler, pos: int)
|
||||
proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTnode)
|
||||
proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTnode)
|
||||
|
@ -429,7 +432,7 @@ proc detectClosureVariable(self: Compiler, name: Name, depth: int = self.scopeDe
|
|||
name.isClosedOver = true
|
||||
|
||||
|
||||
proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool =
|
||||
proc compareTypes(self: Compiler, a, b: Type, strictMutable: bool = true): bool =
|
||||
## Compares two type objects
|
||||
## for equality (works with nil!)
|
||||
|
||||
|
@ -454,17 +457,11 @@ proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool =
|
|||
# Next, we see the type discriminant:
|
||||
# If they're different, then they can't
|
||||
# be the same type!
|
||||
if strictRef:
|
||||
return false
|
||||
else:
|
||||
# Well... unless we don't care about
|
||||
# whether it's a ref/value/mutable type
|
||||
if a.kind in {Reference, Pointer, Mutable}:
|
||||
return self.compareTypes(a.value, b, strictRef)
|
||||
elif b.kind in {Reference, Pointer, Mutable}:
|
||||
return self.compareTypes(a, b.value, strictRef)
|
||||
else:
|
||||
return false
|
||||
return false
|
||||
elif a.mutable != b.mutable and strictMutable:
|
||||
# Are they both (im)mutable? If not,
|
||||
# they're different
|
||||
return false
|
||||
case a.kind:
|
||||
# If all previous checks pass, it's time
|
||||
# to go through each possible type peon
|
||||
|
@ -475,9 +472,9 @@ proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool =
|
|||
# A value type's type is always equal to
|
||||
# another one's
|
||||
return true
|
||||
of Reference, Pointer, Mutable:
|
||||
of Reference, Pointer:
|
||||
# Here we already know that both
|
||||
# a and b are of either of the three
|
||||
# a and b are of either of the two
|
||||
# types in this branch, so we just need
|
||||
# to compare their values
|
||||
return self.compareTypes(a.value, b.value)
|
||||
|
@ -488,7 +485,7 @@ proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool =
|
|||
elif not self.compareTypes(a.returnType, b.returnType):
|
||||
return false
|
||||
for (argA, argB) in zip(a.args, b.args):
|
||||
if not self.compareTypes(argA.kind, argB.kind):
|
||||
if not self.compareTypes(argA.kind, argB.kind, strictMutable):
|
||||
return false
|
||||
return true
|
||||
else:
|
||||
|
@ -537,7 +534,7 @@ proc toIntrinsic(name: string): Type =
|
|||
return nil
|
||||
|
||||
|
||||
proc inferType(self: Compiler, node: LiteralExpr): Type =
|
||||
proc inferType(self: Compiler, node: LiteralExpr, strictMutable: bool = true): Type =
|
||||
## Infers the type of a given literal expression
|
||||
if node.isNil():
|
||||
return nil
|
||||
|
@ -549,7 +546,7 @@ proc inferType(self: Compiler, node: LiteralExpr): Type =
|
|||
if size.len() == 1:
|
||||
return Type(kind: Int64)
|
||||
let typ = size[1].toIntrinsic()
|
||||
if not self.compareTypes(typ, nil):
|
||||
if not self.compareTypes(typ, nil, strictMutable):
|
||||
return typ
|
||||
else:
|
||||
self.error(&"invalid type specifier '{size[1]}' for int")
|
||||
|
@ -560,7 +557,7 @@ proc inferType(self: Compiler, node: LiteralExpr): Type =
|
|||
if size.len() == 1 or size[1] == "f64":
|
||||
return Type(kind: Float64)
|
||||
let typ = size[1].toIntrinsic()
|
||||
if not self.compareTypes(typ, nil):
|
||||
if not self.compareTypes(typ, nil, strictMutable):
|
||||
return typ
|
||||
else:
|
||||
self.error(&"invalid type specifier '{size[1]}' for float")
|
||||
|
@ -578,7 +575,7 @@ proc inferType(self: Compiler, node: LiteralExpr): Type =
|
|||
discard # TODO
|
||||
|
||||
|
||||
proc inferType(self: Compiler, node: Expression): Type =
|
||||
proc inferType(self: Compiler, node: Expression, strictMutable: bool = true): Type =
|
||||
## Infers the type of a given expression and
|
||||
## returns it
|
||||
if node.isNil():
|
||||
|
@ -588,16 +585,16 @@ proc inferType(self: Compiler, node: Expression): Type =
|
|||
let node = IdentExpr(node)
|
||||
let name = self.resolve(node)
|
||||
if not name.isNil():
|
||||
return name.valueType
|
||||
result = name.valueType
|
||||
else:
|
||||
result = node.name.lexeme.toIntrinsic()
|
||||
of unaryExpr:
|
||||
return self.inferType(UnaryExpr(node).a)
|
||||
of binaryExpr:
|
||||
let node = BinaryExpr(node)
|
||||
var a = self.inferType(node.a)
|
||||
var b = self.inferType(node.b)
|
||||
if not self.compareTypes(a, b):
|
||||
var a = self.inferType(node.a, strictMutable)
|
||||
var b = self.inferType(node.b, strictMutable)
|
||||
if not self.compareTypes(a, b, strictMutable):
|
||||
return nil
|
||||
return a
|
||||
of {intExpr, hexExpr, binExpr, octExpr,
|
||||
|
@ -611,7 +608,7 @@ proc inferType(self: Compiler, node: Expression): Type =
|
|||
if not node.returnType.isNil():
|
||||
result.returnType = self.inferType(node.returnType)
|
||||
for argument in node.arguments:
|
||||
result.args.add((argument.name.token.lexeme, self.inferType(argument.valueType)))
|
||||
result.args.add((argument.name.token.lexeme, self.inferType(argument.valueType, strictMutable)))
|
||||
of callExpr:
|
||||
var node = CallExpr(node)
|
||||
case node.callee.kind:
|
||||
|
@ -624,14 +621,21 @@ proc inferType(self: Compiler, node: Expression): Type =
|
|||
else:
|
||||
result = nil
|
||||
of lambdaExpr:
|
||||
result = self.inferType(LambdaExpr(node.callee).returnType)
|
||||
result = self.inferType(LambdaExpr(node.callee).returnType, strictMutable)
|
||||
else:
|
||||
discard # Unreachable
|
||||
of varExpr:
|
||||
result = self.inferType(Var(node).value)
|
||||
result.mutable = true
|
||||
of refExpr:
|
||||
result = Type(kind: Reference, value: self.inferType(Ref(node).value, strictMutable))
|
||||
of ptrExpr:
|
||||
result = Type(kind: Pointer, value: self.inferType(Ptr(node).value, strictMutable))
|
||||
else:
|
||||
discard # Unreachable
|
||||
|
||||
|
||||
proc inferType(self: Compiler, node: Declaration): Type =
|
||||
proc inferType(self: Compiler, node: Declaration, strictMutable: bool = true): Type =
|
||||
## Infers the type of a given declaration
|
||||
## and returns it
|
||||
if node.isNil():
|
||||
|
@ -648,7 +652,7 @@ proc inferType(self: Compiler, node: Declaration): Type =
|
|||
if not resolved.isNil():
|
||||
return resolved.valueType
|
||||
else:
|
||||
return self.inferType(node.value)
|
||||
return self.inferType(node.value, strictMutable)
|
||||
else:
|
||||
return # Unreachable
|
||||
|
||||
|
@ -661,22 +665,26 @@ proc typeToStr(self: Compiler, typ: Type): string =
|
|||
UInt32, Int64, UInt64, Float32, Float64,
|
||||
Char, Byte, String, Nil, TypeKind.Nan, Bool,
|
||||
TypeKind.Inf:
|
||||
return ($typ.kind).toLowerAscii()
|
||||
result &= ($typ.kind).toLowerAscii()
|
||||
of Pointer:
|
||||
return &"ptr {self.typeToStr(typ.value)}"
|
||||
result &= &"ptr {self.typeToStr(typ.value)}"
|
||||
of Reference:
|
||||
return &"ref {self.typeToStr(typ.value)}"
|
||||
of Mutable:
|
||||
return &"var {self.typeToStr(typ.value)}"
|
||||
result &= &"ref {self.typeToStr(typ.value)}"
|
||||
of Function:
|
||||
result = "fn ("
|
||||
result &= "fn ("
|
||||
for i, (argName, argType) in typ.args:
|
||||
result &= &"{argName}: {self.typeToStr(argType)}"
|
||||
result &= &"{argName}: "
|
||||
echo argType[]
|
||||
if argType.mutable:
|
||||
result &= "var "
|
||||
result &= self.typeToStr(argType)
|
||||
if i < typ.args.len() - 1:
|
||||
result &= ", "
|
||||
result &= ")"
|
||||
if not typ.returnType.isNil():
|
||||
result &= &": {self.typeToStr(typ.returnType)}"
|
||||
of Generic:
|
||||
result = typ.node.name.lexeme
|
||||
else:
|
||||
discard
|
||||
|
||||
|
@ -774,19 +782,19 @@ proc findByName(self: Compiler, name: string): seq[Name] =
|
|||
result.add(obj)
|
||||
|
||||
|
||||
proc findByType(self: Compiler, name: string, kind: Type, strictRef: bool = true): seq[Name] =
|
||||
proc findByType(self: Compiler, name: string, kind: Type, strictMutable: bool = true): seq[Name] =
|
||||
## Looks for objects that have already been declared
|
||||
## with the given name and type
|
||||
for obj in self.findByName(name):
|
||||
if self.compareTypes(obj.valueType, kind, strictRef):
|
||||
if self.compareTypes(obj.valueType, kind, strictMutable):
|
||||
result.add(obj)
|
||||
|
||||
|
||||
proc matchImpl(self: Compiler, name: string, kind: Type): Name =
|
||||
proc matchImpl(self: Compiler, name: string, kind: Type, strictMutable: bool = true): Name =
|
||||
## Tries to find a matching function implementation
|
||||
## compatible with the given type and returns its
|
||||
## name object
|
||||
let impl = self.findByType(name, kind, strictRef=false)
|
||||
let impl = self.findByType(name, kind, strictMutable)
|
||||
if impl.len() == 0:
|
||||
var msg = &"cannot find a suitable implementation for '{name}'"
|
||||
let names = self.findByName(name)
|
||||
|
@ -803,7 +811,9 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
|
|||
msg &= &", wrong number of arguments ({name.valueType.args.len()} expected, got {kind.args.len()})"
|
||||
else:
|
||||
for i, arg in kind.args:
|
||||
if name.valueType.args[i].kind.kind == Mutable and arg.kind.kind != Mutable:
|
||||
echo name.valueType.args[i].kind.mutable
|
||||
echo arg.kind.mutable
|
||||
if name.valueType.args[i].kind.mutable and not arg.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):
|
||||
|
@ -991,16 +1001,16 @@ proc callBinaryOp(self: Compiler, fn: Name, op: BinaryExpr) =
|
|||
proc unary(self: Compiler, node: UnaryExpr) =
|
||||
## Compiles unary expressions such as decimal
|
||||
## and bitwise negation
|
||||
let valueType = self.inferType(node.a)
|
||||
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", valueType)]))
|
||||
let valueType = self.inferType(node.a, strictMutable=false)
|
||||
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", valueType)]), strictMutable=false)
|
||||
self.callUnaryOp(funct, node)
|
||||
|
||||
|
||||
proc binary(self: Compiler, node: BinaryExpr) =
|
||||
## Compiles all binary expressions
|
||||
let typeOfA = self.inferType(node.a)
|
||||
let typeOfB = self.inferType(node.b)
|
||||
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", typeOfA), ("", typeOfB)]))
|
||||
let typeOfA = self.inferType(node.a, strictMutable=false)
|
||||
let typeOfB = self.inferType(node.b, strictMutable=false)
|
||||
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", typeOfA), ("", typeOfB)]), strictMutable=false)
|
||||
self.callBinaryOp(funct, node)
|
||||
|
||||
|
||||
|
@ -1035,9 +1045,8 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
|||
isLet: node.isLet,
|
||||
isClosedOver: false,
|
||||
line: node.token.line))
|
||||
# TODO:
|
||||
# if mutable:
|
||||
# self.names[^1].valueType = Type(kind: Mutable, value: self.names[^1].valueType)
|
||||
if mutable:
|
||||
self.names[^1].valueType.mutable = true
|
||||
# We emit a jump of 0 because this may become a
|
||||
# StoreHeap instruction. If they variable is
|
||||
# not closed over, we'll sadly be wasting a
|
||||
|
@ -1055,6 +1064,16 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
|||
self.emitBytes(0.toTriple())
|
||||
of NodeKind.funDecl:
|
||||
var node = FunDecl(node)
|
||||
# We declare the generics before the function so we
|
||||
# can refer to them
|
||||
for gen in node.generics:
|
||||
self.names.add(Name(depth: self.scopeDepth + 1,
|
||||
isPrivate: true,
|
||||
isConst: false,
|
||||
owner: self.currentModule,
|
||||
line: node.token.line,
|
||||
valueType: Type(kind: Generic, mutable: false, node: gen.name),
|
||||
name: gen.name))
|
||||
self.names.add(Name(depth: self.scopeDepth,
|
||||
isPrivate: node.isPrivate,
|
||||
isConst: false,
|
||||
|
@ -1070,10 +1089,6 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
|||
isClosedOver: false,
|
||||
line: node.token.line))
|
||||
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
|
||||
for argument in node.arguments:
|
||||
if self.names.high() > 16777215:
|
||||
|
@ -1094,18 +1109,6 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
|
|||
isFunctionArgument: true)
|
||||
self.names.add(name)
|
||||
name.valueType = self.inferType(argument.valueType)
|
||||
if argument.mutable:
|
||||
name.valueType = Type(kind: Mutable, value: name.valueType)
|
||||
elif argument.isRef:
|
||||
name.valueType = Type(kind: Reference, value: name.valueType)
|
||||
elif argument.isPtr:
|
||||
name.valueType = Type(kind: Pointer, value: name.valueType)
|
||||
# We check if the argument's type is a generic
|
||||
if name.valueType.isNil() and argument.valueType.kind == identExpr:
|
||||
for gen in node.generics:
|
||||
if gen.name == IdentExpr(argument.valueType):
|
||||
name.valueType = Type(kind: Generic)
|
||||
break
|
||||
# If it's still nil, it's an error!
|
||||
if name.valueType.isNil():
|
||||
self.error(&"cannot determine the type of argument '{argument.name.token.lexeme}'")
|
||||
|
@ -1340,6 +1343,7 @@ proc callExpr(self: Compiler, node: CallExpr) =
|
|||
var args: seq[tuple[name: string, kind: Type]] = @[]
|
||||
var argExpr: seq[Expression] = @[]
|
||||
var kind: Type
|
||||
var strictMutable = true
|
||||
# TODO: Keyword arguments
|
||||
for i, argument in node.arguments.positionals:
|
||||
kind = self.inferType(argument)
|
||||
|
@ -1347,6 +1351,8 @@ proc callExpr(self: Compiler, node: CallExpr) =
|
|||
if argument.kind == identExpr:
|
||||
self.error(&"reference to undeclared identifier '{IdentExpr(argument).name.lexeme}'")
|
||||
self.error(&"cannot infer the type of argument {i + 1} in function call")
|
||||
if kind.mutable:
|
||||
strictMutable = false
|
||||
args.add(("", kind))
|
||||
argExpr.add(argument)
|
||||
for argument in node.arguments.keyword:
|
||||
|
@ -1356,7 +1362,7 @@ proc callExpr(self: Compiler, node: CallExpr) =
|
|||
var funct: Name
|
||||
case node.callee.kind:
|
||||
of identExpr:
|
||||
funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
|
||||
funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args), strictMutable)
|
||||
of NodeKind.callExpr:
|
||||
var node = node.callee
|
||||
while node.kind == callExpr:
|
||||
|
@ -1464,8 +1470,6 @@ proc returnStmt(self: Compiler, node: ReturnStmt) =
|
|||
let actual = self.inferType(node.value)
|
||||
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
|
||||
if actual.isNil() and not expected.returnType.isNil():
|
||||
if not node.value.isNil():
|
||||
|
@ -1621,13 +1625,13 @@ proc varDecl(self: Compiler, node: VarDecl) =
|
|||
name = CallExpr(node.value).callee.token.lexeme
|
||||
self.error(&"reference to undeclared identifier '{name}'")
|
||||
self.error(&"'{node.name.token.lexeme}' has no type")
|
||||
elif not expected.isNil() and expected.kind == Mutable: # I mean, variables *are* already mutable (some of them anyway)
|
||||
elif not expected.isNil() and expected.mutable: # I mean, variables *are* already mutable (some of them anyway)
|
||||
self.error(&"invalid type '{self.typeToStr(expected)}' for var")
|
||||
elif not self.compareTypes(expected, actual):
|
||||
if not expected.isNil():
|
||||
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.declareName(node, mutable=node.token.kind == Var)
|
||||
self.declareName(node, mutable=node.token.kind == TokenType.Var)
|
||||
self.emitByte(StoreVar)
|
||||
self.emitBytes(self.names.len().toTriple())
|
||||
|
||||
|
@ -1683,6 +1687,16 @@ proc funDecl(self: Compiler, node: FunDecl) =
|
|||
## Compiles function declarations
|
||||
var function = self.currentFunction
|
||||
self.declareName(node)
|
||||
if node.generics.len() > 0:
|
||||
# We can't know the type of
|
||||
# generic arguments yet, so
|
||||
# we wait for the function to
|
||||
# be called to compile its code
|
||||
# or dispatch any pragmas. We
|
||||
# still declare its name so that
|
||||
# it can be assigned to variables
|
||||
# and passed to functions
|
||||
return
|
||||
self.dispatchPragmas(node)
|
||||
let fn = self.names[^(node.arguments.len() + 1)]
|
||||
var jmp: int
|
||||
|
|
|
@ -77,7 +77,10 @@ type
|
|||
nanExpr,
|
||||
infExpr,
|
||||
identExpr, # Identifier
|
||||
pragmaExpr
|
||||
pragmaExpr,
|
||||
varExpr,
|
||||
refExpr,
|
||||
ptrExpr
|
||||
|
||||
# Here I would've rather used object variants, and in fact that's what was in
|
||||
# place before, but not being able to re-declare a field of the same type in
|
||||
|
@ -152,6 +155,7 @@ type
|
|||
callee*: Expression # The object being called
|
||||
arguments*: tuple[positionals: seq[Expression], keyword: seq[tuple[
|
||||
name: IdentExpr, value: Expression]]]
|
||||
genericArgs*: seq[Expression]
|
||||
|
||||
UnaryExpr* = ref object of Expression
|
||||
operator*: Token
|
||||
|
@ -171,8 +175,7 @@ type
|
|||
|
||||
LambdaExpr* = ref object of Expression
|
||||
body*: Statement
|
||||
arguments*: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]]
|
||||
arguments*: seq[tuple[name: IdentExpr, valueType: Expression]]
|
||||
defaults*: seq[Expression]
|
||||
isGenerator*: bool
|
||||
isAsync*: bool
|
||||
|
@ -253,8 +256,7 @@ type
|
|||
FunDecl* = ref object of Declaration
|
||||
name*: IdentExpr
|
||||
body*: Statement
|
||||
arguments*: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]]
|
||||
arguments*: seq[tuple[name: IdentExpr, valueType: Expression]]
|
||||
defaults*: seq[Expression]
|
||||
isAsync*: bool
|
||||
isGenerator*: bool
|
||||
|
@ -264,14 +266,22 @@ type
|
|||
|
||||
TypeDecl* = ref object of Declaration
|
||||
name*: IdentExpr
|
||||
fields*: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool, isPrivate: bool]]
|
||||
fields*: seq[tuple[name: IdentExpr, valueType: Expression, isPrivate: bool]]
|
||||
defaults*: seq[Expression]
|
||||
isRef*: bool
|
||||
valueType*: Expression
|
||||
|
||||
Pragma* = ref object of Expression
|
||||
name*: IdentExpr
|
||||
args*: seq[LiteralExpr]
|
||||
|
||||
Var* = ref object of Expression
|
||||
value*: Expression
|
||||
|
||||
Ref* = ref object of Expression
|
||||
value*: Expression
|
||||
|
||||
Ptr* = ref object of Expression
|
||||
value*: Expression
|
||||
|
||||
|
||||
proc isConst*(self: ASTNode): bool =
|
||||
|
@ -311,6 +321,27 @@ proc newPragma*(name: IdentExpr, args: seq[LiteralExpr]): Pragma =
|
|||
result.token = name.token
|
||||
|
||||
|
||||
proc newVarExpr*(expression: Expression, token: Token): Var =
|
||||
new(result)
|
||||
result.kind = varExpr
|
||||
result.value = expression
|
||||
result.token = token
|
||||
|
||||
|
||||
proc newRefExpr*(expression: Expression, token: Token): Ref =
|
||||
new(result)
|
||||
result.kind = refExpr
|
||||
result.value = expression
|
||||
result.token = token
|
||||
|
||||
|
||||
proc newPtrExpr*(expression: Expression, token: Token): Ptr =
|
||||
new(result)
|
||||
result.kind = ptrExpr
|
||||
result.value = expression
|
||||
result.token = token
|
||||
|
||||
|
||||
proc newIntExpr*(literal: Token): IntExpr =
|
||||
result = IntExpr(kind: intExpr)
|
||||
result.literal = literal
|
||||
|
@ -377,11 +408,10 @@ proc newGroupingExpr*(expression: Expression, token: Token): GroupingExpr =
|
|||
result.token = token
|
||||
|
||||
|
||||
proc newLambdaExpr*(arguments: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]], defaults: seq[Expression],
|
||||
body: Statement, isGenerator: bool, isAsync: bool, token: Token,
|
||||
returnType: Expression, pragmas: seq[Pragma],
|
||||
generics: seq[tuple[name: IdentExpr, cond: Expression]]): LambdaExpr =
|
||||
proc newLambdaExpr*(arguments: seq[tuple[name: IdentExpr, valueType: Expression]],
|
||||
defaults: seq[Expression], body: Statement, isGenerator: bool,
|
||||
isAsync: bool, token: Token, returnType: Expression, pragmas: seq[Pragma],
|
||||
generics: seq[tuple[name: IdentExpr, cond: Expression]]): LambdaExpr =
|
||||
result = LambdaExpr(kind: lambdaExpr)
|
||||
result.body = body
|
||||
result.arguments = arguments
|
||||
|
@ -414,15 +444,15 @@ proc newSetItemExpr*(obj: Expression, name: IdentExpr, value: Expression,
|
|||
|
||||
proc newCallExpr*(callee: Expression, arguments: tuple[positionals: seq[
|
||||
Expression], keyword: seq[tuple[name: IdentExpr, value: Expression]]],
|
||||
token: Token): CallExpr =
|
||||
token: Token, genericArgs: seq[Expression] = @[]): CallExpr =
|
||||
result = CallExpr(kind: callExpr)
|
||||
result.callee = callee
|
||||
result.arguments = arguments
|
||||
result.token = token
|
||||
result.genericArgs = @[]
|
||||
|
||||
|
||||
proc newSliceExpr*(expression: Expression, ends: seq[Expression],
|
||||
token: Token): SliceExpr =
|
||||
proc newSliceExpr*(expression: Expression, ends: seq[Expression], token: Token): SliceExpr =
|
||||
result = SliceExpr(kind: sliceExpr)
|
||||
result.expression = expression
|
||||
result.ends = ends
|
||||
|
@ -579,7 +609,7 @@ proc newVarDecl*(name: IdentExpr, value: Expression, isConst: bool = false,
|
|||
result.pragmas = pragmas
|
||||
|
||||
|
||||
proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool]], defaults: seq[Expression],
|
||||
proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueType: Expression]], defaults: seq[Expression],
|
||||
body: Statement, isAsync, isGenerator: bool,
|
||||
isPrivate: bool, token: Token, pragmas: seq[Pragma],
|
||||
returnType: Expression, generics: seq[tuple[name: IdentExpr, cond: Expression]]): FunDecl =
|
||||
|
@ -598,9 +628,9 @@ proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueTyp
|
|||
result.generics = generics
|
||||
|
||||
|
||||
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool, isPrivate: bool]],
|
||||
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, isPrivate: bool]],
|
||||
defaults: seq[Expression], isPrivate: bool, token: Token, pragmas: seq[Pragma],
|
||||
generics: seq[tuple[name: IdentExpr, cond: Expression]], isRef: bool): TypeDecl =
|
||||
generics: seq[tuple[name: IdentExpr, cond: Expression]], valueType: Expression): TypeDecl =
|
||||
result = TypeDecl(kind: typeDecl)
|
||||
result.name = name
|
||||
result.fields = fields
|
||||
|
@ -609,8 +639,7 @@ proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType:
|
|||
result.token = token
|
||||
result.pragmas = pragmas
|
||||
result.generics = generics
|
||||
result.isRef = isRef
|
||||
|
||||
result.valueType = valueType
|
||||
|
||||
|
||||
proc `$`*(self: ASTNode): string =
|
||||
|
@ -699,7 +728,7 @@ proc `$`*(self: ASTNode): string =
|
|||
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}, pragmas={self.pragmas})"""
|
||||
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}, pragmas={self.pragmas})"""
|
||||
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, defaults={self.defaults}, private={self.isPrivate}, pragmas={self.pragmas}, generics={self.generics}, pragmas={self.pragmas}, type={self.valueType})"""
|
||||
of lambdaExpr:
|
||||
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}, pragmas={self.pragmas})"""
|
||||
|
@ -724,6 +753,12 @@ proc `$`*(self: ASTNode): string =
|
|||
of pragmaExpr:
|
||||
var self = Pragma(self)
|
||||
result &= &"Pragma(name={self.name}, args={self.args})"
|
||||
of varExpr:
|
||||
result &= &"Var({Var(self).value})"
|
||||
of refExpr:
|
||||
result &= &"Ptr({Ref(self).value})"
|
||||
of ptrExpr:
|
||||
result &= &"Ptr({Ptr(self).value})"
|
||||
else:
|
||||
discard
|
||||
|
||||
|
|
|
@ -91,6 +91,10 @@ type
|
|||
LoadNan,
|
||||
LoadInf,
|
||||
## Operations on primitive types
|
||||
NegInt64, # No unsigned variants (how would you negate something that has no sign?)
|
||||
NegInt32,
|
||||
NegInt16,
|
||||
NegInt8,
|
||||
AddInt64,
|
||||
AddUInt64,
|
||||
AddInt32,
|
||||
|
|
|
@ -349,19 +349,27 @@ proc primary(self: Parser): Expression =
|
|||
result = newInfExpr(self.step())
|
||||
of Function:
|
||||
discard self.step()
|
||||
result = Expression(self.funDecl(isLambda = true))
|
||||
result = Expression(self.funDecl(isLambda=true))
|
||||
of Coroutine:
|
||||
discard self.step()
|
||||
result = Expression(self.funDecl(isAsync = true, isLambda = true))
|
||||
result = Expression(self.funDecl(isAsync=true, isLambda=true))
|
||||
of Generator:
|
||||
discard self.step()
|
||||
result = Expression(self.funDecl(isGenerator = true,
|
||||
isLambda = true))
|
||||
result = Expression(self.funDecl(isGenerator=true, isLambda=true))
|
||||
of TokenType.Var:
|
||||
discard self.step()
|
||||
result = newVarExpr(self.expression(), self.peek(-1))
|
||||
of TokenType.Ref:
|
||||
discard self.step()
|
||||
result = newRefExpr(self.expression(), self.peek(-1))
|
||||
of TokenType.Ptr:
|
||||
discard self.step()
|
||||
result = newPtrExpr(self.expression(), self.peek(-1))
|
||||
else:
|
||||
self.error("invalid syntax")
|
||||
|
||||
|
||||
proc makeCall(self: Parser, callee: Expression): Expression =
|
||||
proc makeCall(self: Parser, callee: Expression): CallExpr =
|
||||
## Utility function called iteratively by self.call()
|
||||
## to parse a function call
|
||||
let tok = self.peek(-1)
|
||||
|
@ -394,9 +402,15 @@ proc makeCall(self: Parser, callee: Expression): Expression =
|
|||
result = newCallExpr(callee, arguments, tok)
|
||||
|
||||
|
||||
proc parseGenericArgs(self: Parser) =
|
||||
## Parses function generic arguments
|
||||
## like function[type](arg)
|
||||
discard
|
||||
|
||||
|
||||
proc call(self: Parser): Expression =
|
||||
## Parses function calls, object field
|
||||
## accessing and slicing expressions
|
||||
## Parses function calls and object field
|
||||
## accessing
|
||||
result = self.primary()
|
||||
while true:
|
||||
if self.match(LeftParen):
|
||||
|
@ -404,6 +418,9 @@ proc call(self: Parser): Expression =
|
|||
elif self.match(Dot):
|
||||
self.expect(Identifier, "expecting attribute name after '.'")
|
||||
result = newGetItemExpr(result, newIdentExpr(self.peek(-1)), self.peek(-1))
|
||||
elif self.match(LeftBracket):
|
||||
self.parseGenericArgs() # TODO
|
||||
result = self.makeCall(result)
|
||||
else:
|
||||
break
|
||||
|
||||
|
@ -707,7 +724,7 @@ proc forStmt(self: Parser): Statement =
|
|||
var increment: Expression = nil
|
||||
if self.match(Semicolon):
|
||||
discard
|
||||
elif self.match(Var):
|
||||
elif self.match(TokenType.Var):
|
||||
initializer = self.varDecl()
|
||||
if not VarDecl(initializer).isPrivate:
|
||||
self.error("cannot declare public for loop initializer")
|
||||
|
@ -835,7 +852,7 @@ proc varDecl(self: Parser, isLet: bool = false,
|
|||
if isConst and not value.isConst():
|
||||
self.error("constant initializer is not a constant")
|
||||
else:
|
||||
if tok.kind != Var:
|
||||
if tok.kind != TokenType.Var:
|
||||
self.error(&"{tok.lexeme} declaration requires an initializer")
|
||||
value = newNilExpr(Token(lexeme: "nil"))
|
||||
self.expect(Semicolon, "expecting semicolon after declaration")
|
||||
|
@ -843,7 +860,7 @@ proc varDecl(self: Parser, isLet: bool = false,
|
|||
for pragma in self.parsePragmas():
|
||||
pragmas.add(pragma)
|
||||
case tok.kind:
|
||||
of Var:
|
||||
of TokenType.Var:
|
||||
result = newVarDecl(name, value, isPrivate = isPrivate, token = tok,
|
||||
valueType = valueType, pragmas = (@[]))
|
||||
of Const:
|
||||
|
@ -859,10 +876,8 @@ proc varDecl(self: Parser, isLet: bool = false,
|
|||
result.pragmas = pragmas
|
||||
|
||||
|
||||
proc parseDeclArguments(self: Parser, arguments: var seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool]],
|
||||
parameter: var tuple[name: IdentExpr,
|
||||
valueType: Expression, mutable: bool,
|
||||
isRef: bool, isPtr: bool],
|
||||
proc parseDeclArguments(self: Parser, arguments: var seq[tuple[name: IdentExpr, valueType: Expression]],
|
||||
parameter: var tuple[name: IdentExpr, valueType: Expression],
|
||||
defaults: var seq[Expression]) =
|
||||
## Helper to parse declaration arguments and avoid code duplication
|
||||
while not self.check(RightParen):
|
||||
|
@ -871,21 +886,11 @@ proc parseDeclArguments(self: Parser, arguments: var seq[tuple[name: IdentExpr,
|
|||
self.expect(Identifier, "expecting parameter name")
|
||||
parameter.name = newIdentExpr(self.peek(-1))
|
||||
if self.match(":"):
|
||||
parameter.mutable = false
|
||||
parameter.isPtr = false
|
||||
parameter.isRef = false
|
||||
if self.match(Var):
|
||||
parameter.mutable = true
|
||||
elif self.match(Ptr):
|
||||
parameter.isPtr = true
|
||||
elif self.match(Ref):
|
||||
parameter.isRef = true
|
||||
parameter.valueType = self.expression()
|
||||
for i in countdown(arguments.high(), 0):
|
||||
if arguments[i].valueType != nil:
|
||||
break
|
||||
arguments[i].valueType = parameter.valueType
|
||||
arguments[i].mutable = parameter.mutable
|
||||
else:
|
||||
parameter.valueType = nil
|
||||
if parameter in arguments:
|
||||
|
@ -907,14 +912,12 @@ proc parseFunExpr(self: Parser): LambdaExpr =
|
|||
## Parses the return value of a function
|
||||
## when it is another function. Works
|
||||
## recursively
|
||||
var arguments: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]] = @[]
|
||||
var arguments: seq[tuple[name: IdentExpr, valueType: Expression]] = @[]
|
||||
var defaults: seq[Expression] = @[]
|
||||
result = newLambdaExpr(arguments, defaults, nil, isGenerator = self.peek(-1).kind == Generator,
|
||||
isAsync = self.peek(-1).kind == Coroutine, token = self.peek(-1),
|
||||
returnType = nil, pragmas = (@[]), generics=(@[]))
|
||||
var parameter: tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]
|
||||
result = newLambdaExpr(arguments, defaults, nil, isGenerator=self.peek(-1).kind == Generator,
|
||||
isAsync=self.peek(-1).kind == Coroutine, token=self.peek(-1),
|
||||
returnType=nil, pragmas=(@[]), generics=(@[]))
|
||||
var parameter: tuple[name: IdentExpr, valueType: Expression]
|
||||
if self.match(LeftParen):
|
||||
self.parseDeclArguments(arguments, parameter, defaults)
|
||||
if self.match(":"):
|
||||
|
@ -944,8 +947,7 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
## (with or without a name, where applicable)
|
||||
let tok = self.peek(-1)
|
||||
var enclosingFunction = self.currentFunction
|
||||
var arguments: seq[tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]] = @[]
|
||||
var arguments: seq[tuple[name: IdentExpr, valueType: Expression]] = @[]
|
||||
var defaults: seq[Expression] = @[]
|
||||
var returnType: Expression
|
||||
var pragmas: seq[Pragma] = @[]
|
||||
|
@ -957,11 +959,11 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
# are nameless, so we can sort the ambiguity by checking
|
||||
# if there's an identifier after the keyword
|
||||
self.currentFunction = newFunDecl(newIdentExpr(self.peek(-1)), arguments, defaults, newBlockStmt(@[], Token()),
|
||||
isAsync = isAsync,
|
||||
isGenerator = isGenerator,
|
||||
isPrivate = true,
|
||||
token = tok, pragmas = (@[]),
|
||||
returnType = nil,
|
||||
isAsync=isAsync,
|
||||
isGenerator=isGenerator,
|
||||
isPrivate=true,
|
||||
token=tok, pragmas=(@[]),
|
||||
returnType=nil,
|
||||
generics=(@[]))
|
||||
if self.match("*"):
|
||||
FunDecl(self.currentFunction).isPrivate = false
|
||||
|
@ -996,8 +998,7 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
else:
|
||||
returnType = self.expression()
|
||||
if self.match(LeftParen):
|
||||
var parameter: tuple[name: IdentExpr, valueType: Expression,
|
||||
mutable: bool, isRef: bool, isPtr: bool]
|
||||
var parameter: tuple[name: IdentExpr, valueType: Expression]
|
||||
self.parseDeclArguments(arguments, parameter, defaults)
|
||||
if self.match(":"):
|
||||
# Function's return type
|
||||
|
@ -1122,55 +1123,30 @@ proc typeDecl(self: Parser): TypeDecl =
|
|||
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 fields: seq[tuple[name: IdentExpr, valueType: Expression, 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)
|
||||
result = newTypeDecl(name, fields, defaults, isPrivate, token, pragmas, generics, nil)
|
||||
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")
|
||||
result.valueType = self.expression()
|
||||
self.expect(LeftBrace, "expecting '{' after type declaration")
|
||||
if self.match(TokenType.Pragma):
|
||||
for pragma in self.parsePragmas():
|
||||
pragmas.add(pragma)
|
||||
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))
|
||||
result.fields.add((argName, argType, argPrivate))
|
||||
if self.match("="):
|
||||
result.defaults.add(self.expression())
|
||||
self.expect(";", "expecting semicolon after field declaration")
|
||||
|
@ -1180,7 +1156,7 @@ proc typeDecl(self: Parser): TypeDecl =
|
|||
proc declaration(self: Parser): Declaration =
|
||||
## Parses declarations
|
||||
case self.peek().kind:
|
||||
of Var, Const, Let:
|
||||
of TokenType.Var, Const, Let:
|
||||
let keyword = self.step()
|
||||
result = self.varDecl(isLet = keyword.kind == Let,
|
||||
isConst = keyword.kind == Const)
|
||||
|
|
|
@ -400,7 +400,7 @@ proc fillSymbolTable(tokenizer: Lexer) =
|
|||
tokenizer.symbols.addKeyword("assert", TokenType.Assert)
|
||||
tokenizer.symbols.addKeyword("const", Const)
|
||||
tokenizer.symbols.addKeyword("let", Let)
|
||||
tokenizer.symbols.addKeyword("var", Var)
|
||||
tokenizer.symbols.addKeyword("var", TokenType.Var)
|
||||
tokenizer.symbols.addKeyword("import", Import)
|
||||
tokenizer.symbols.addKeyword("yield", TokenType.Yield)
|
||||
tokenizer.symbols.addKeyword("return", TokenType.Return)
|
||||
|
@ -415,8 +415,8 @@ proc fillSymbolTable(tokenizer: Lexer) =
|
|||
tokenizer.symbols.addKeyword("nil", TokenType.Nil)
|
||||
tokenizer.symbols.addKeyword("true", True)
|
||||
tokenizer.symbols.addKeyword("false", False)
|
||||
tokenizer.symbols.addKeyword("ref", Ref)
|
||||
tokenizer.symbols.addKeyword("ptr", Ptr)
|
||||
tokenizer.symbols.addKeyword("ref", TokenType.Ref)
|
||||
tokenizer.symbols.addKeyword("ptr", TokenType.Ptr)
|
||||
for sym in [">", "<", "=", "~", "/", "+", "-", "_", "*", "?", "@", ":"]:
|
||||
tokenizer.symbols.addSymbol(sym, Symbol)
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
## Builtin arithmetic operators for Peon
|
||||
|
||||
# Note: These do nothing on their own. All they do
|
||||
# is serve as placeholders for emitting specific VM
|
||||
# instructions. They're implemented this way because:
|
||||
# - They tie into the existing type system nicely
|
||||
# - It makes the implementation easier and more flexible
|
||||
|
||||
|
||||
operator `+`(a, b: int): int {
|
||||
#pragma[magic: "AddInt64", pure]
|
||||
|
|
|
@ -12,5 +12,5 @@ operator `+`(a, b: int): int {
|
|||
|
||||
|
||||
getFunction()(5);
|
||||
var x = `+`;
|
||||
x(1, 2);
|
||||
var x = getFunction;
|
||||
x()(3);
|
|
@ -0,0 +1,24 @@
|
|||
operator `=`[T](a: var T, b: T) {
|
||||
#pragma[magic: "GenericAssign"]
|
||||
}
|
||||
|
||||
|
||||
operator `+`(a, b: int): int {
|
||||
#pragma[magic: "AddInt64", pure]
|
||||
}
|
||||
|
||||
|
||||
operator `+=`(a: var int, b: int) {
|
||||
a = a + b;
|
||||
}
|
||||
|
||||
|
||||
fn identity(x: var int): int {
|
||||
x += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
var x = 5;
|
||||
identity(x);
|
||||
# identity(38); # If you uncomment this, the compiler errors out!
|
Loading…
Reference in New Issue