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