Many fixes to generics

This commit is contained in:
Mattia Giambirtone 2022-12-01 22:04:10 +01:00
parent 63cdda42ce
commit 8fb90bb0ef
12 changed files with 356 additions and 419 deletions

File diff suppressed because it is too large Load Diff

View File

@ -668,6 +668,7 @@ proc lex*(self: Lexer, source, file: string): seq[Token] =
self.start = self.current self.start = self.current
self.lineCurrent = self.linePos self.lineCurrent = self.linePos
self.tokens.add(Token(kind: EndOfFile, lexeme: "", self.tokens.add(Token(kind: EndOfFile, lexeme: "",
line: self.line, pos: (self.current, self.current))) line: self.line, pos: (self.current, self.current),
relPos: (start: 0, stop: self.linePos - 1)))
self.incLine() self.incLine()
return self.tokens return self.tokens

View File

@ -73,12 +73,8 @@ type
hexExpr, hexExpr,
octExpr, octExpr,
binExpr, binExpr,
nilExpr,
nanExpr,
infExpr,
identExpr, # Identifier identExpr, # Identifier
pragmaExpr, pragmaExpr,
varExpr,
refExpr, refExpr,
ptrExpr ptrExpr
@ -131,9 +127,6 @@ type
TrueExpr* = ref object of LiteralExpr TrueExpr* = ref object of LiteralExpr
FalseExpr* = ref object of LiteralExpr FalseExpr* = ref object of LiteralExpr
NilExpr* = ref object of LiteralExpr
NanExpr* = ref object of LiteralExpr
InfExpr* = ref object of LiteralExpr
IdentExpr* = ref object of Expression IdentExpr* = ref object of Expression
name*: Token name*: Token
@ -300,19 +293,12 @@ proc isConst*(self: ASTNode): bool =
## constants ## constants
case self.kind: case self.kind:
of intExpr, hexExpr, binExpr, octExpr, strExpr, falseExpr, trueExpr, of intExpr, hexExpr, binExpr, octExpr, strExpr, falseExpr, trueExpr,
infExpr, nanExpr, floatExpr, nilExpr: floatExpr:
return true return true
else: else:
return false return false
proc isLiteral*(self: ASTNode): bool {.inline.} =
## Returns if the AST node represents a literal
self.kind in {intExpr, hexExpr, binExpr, octExpr,
strExpr, falseExpr, trueExpr, infExpr,
nanExpr, floatExpr, nilExpr
}
## AST node constructors ## AST node constructors
proc newASTNode*(kind: NodeKind, token: Token): ASTNode = proc newASTNode*(kind: NodeKind, token: Token): ASTNode =
## Initializes a new generic ASTNode object ## Initializes a new generic ASTNode object
@ -329,13 +315,6 @@ 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 = proc newRefExpr*(expression: Expression, token: Token): Ref =
new(result) new(result)
result.kind = refExpr result.kind = refExpr
@ -384,12 +363,6 @@ proc newTrueExpr*(token: Token): LiteralExpr = LiteralExpr(kind: trueExpr,
token: token, literal: token) token: token, literal: token)
proc newFalseExpr*(token: Token): LiteralExpr = LiteralExpr(kind: falseExpr, proc newFalseExpr*(token: Token): LiteralExpr = LiteralExpr(kind: falseExpr,
token: token, literal: token) token: token, literal: token)
proc newNaNExpr*(token: Token): LiteralExpr = LiteralExpr(kind: nanExpr,
token: token, literal: token)
proc newNilExpr*(token: Token): LiteralExpr = LiteralExpr(kind: nilExpr,
token: token, literal: token)
proc newInfExpr*(token: Token): LiteralExpr = LiteralExpr(kind: infExpr,
token: token, literal: token)
proc newStrExpr*(literal: Token): StrExpr = proc newStrExpr*(literal: Token): StrExpr =
@ -667,8 +640,8 @@ proc `$`*(self: ASTNode): string =
return "nil" return "nil"
case self.kind: case self.kind:
of intExpr, floatExpr, hexExpr, binExpr, octExpr, strExpr, trueExpr, of intExpr, floatExpr, hexExpr, binExpr, octExpr, strExpr, trueExpr,
falseExpr, nanExpr, nilExpr, infExpr: falseExpr:
if self.kind in {trueExpr, falseExpr, nanExpr, nilExpr, infExpr}: if self.kind in {trueExpr, falseExpr}:
result &= &"Literal({($self.kind)[0..^5]})" result &= &"Literal({($self.kind)[0..^5]})"
elif self.kind == strExpr: elif self.kind == strExpr:
result &= &"Literal({LiteralExpr(self).literal.lexeme[1..^2].escape()})" result &= &"Literal({LiteralExpr(self).literal.lexeme[1..^2].escape()})"
@ -773,10 +746,8 @@ 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: of refExpr:
result &= &"Ptr({Ref(self).value})" result &= &"Ref({Ref(self).value})"
of ptrExpr: of ptrExpr:
result &= &"Ptr({Ptr(self).value})" result &= &"Ptr({Ptr(self).value})"
else: else:

View File

@ -271,7 +271,7 @@ const argumentDoubleInstructions* = {PopN, }
# Jump instructions jump at relative or absolute bytecode offsets # Jump instructions jump at relative or absolute bytecode offsets
const jumpInstructions* = {Jump, JumpIfFalse, JumpIfFalsePop, const jumpInstructions* = {Jump, JumpIfFalse, JumpIfFalsePop,
JumpForwards, JumpBackwards, JumpForwards, JumpBackwards,
JumpIfTrue} JumpIfTrue, JumpIfFalseOrPop}
proc newChunk*: Chunk = proc newChunk*: Chunk =

View File

@ -24,9 +24,6 @@ type
# Booleans # Booleans
True, False, True, False,
# Other singleton types
Infinity, NotANumber, Nil
# Control flow statements # Control flow statements
If, Else, If, Else,

View File

@ -317,10 +317,6 @@ proc primary(self: Parser): Expression =
result = newTrueExpr(self.step()) result = newTrueExpr(self.step())
of False: of False:
result = newFalseExpr(self.step()) result = newFalseExpr(self.step())
of TokenType.NotANumber:
result = newNanExpr(self.step())
of Nil:
result = newNilExpr(self.step())
of Float: of Float:
result = newFloatExpr(self.step()) result = newFloatExpr(self.step())
of Integer: of Integer:
@ -343,7 +339,7 @@ proc primary(self: Parser): Expression =
result = newYieldExpr(self.expression(), tok) result = newYieldExpr(self.expression(), tok)
else: else:
# Empty yield # Empty yield
result = newYieldExpr(newNilExpr(Token()), tok) result = newYieldExpr(nil, tok)
of Await: of Await:
let tok = self.step() let tok = self.step()
if self.currentFunction.isNil(): if self.currentFunction.isNil():
@ -364,8 +360,6 @@ proc primary(self: Parser): Expression =
result = newBinExpr(self.step()) result = newBinExpr(self.step())
of String: of String:
result = newStrExpr(self.step()) result = newStrExpr(self.step())
of Infinity:
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))
@ -375,9 +369,6 @@ proc primary(self: Parser): Expression =
of Generator: of Generator:
discard self.step() 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: of TokenType.Ref:
discard self.step() discard self.step()
result = newRefExpr(self.expression(), self.peek(-1)) result = newRefExpr(self.expression(), self.peek(-1))
@ -654,7 +645,7 @@ proc yieldStmt(self: Parser): Statement =
if not self.check(Semicolon): if not self.check(Semicolon):
result = newYieldStmt(self.expression(), tok) result = newYieldStmt(self.expression(), tok)
else: else:
result = newYieldStmt(newNilExpr(Token(lexeme: "nil")), tok) result = newYieldStmt(nil, tok)
endOfLine("missing semicolon after 'yield'") endOfLine("missing semicolon after 'yield'")
@ -857,7 +848,8 @@ proc parsePragmas(self: Parser): seq[Pragma] =
elif self.match("("): elif self.match("("):
while not self.match(")") and not self.done(): while not self.match(")") and not self.done():
exp = self.primary() exp = self.primary()
if not exp.isLiteral(): if exp.kind notin {strExpr, intExpr, octExpr, binExpr, hexExpr, floatExpr,
trueExpr, falseExpr}:
self.error("pragma arguments can only be literals", exp.token) self.error("pragma arguments can only be literals", exp.token)
args.add(LiteralExpr(exp)) args.add(LiteralExpr(exp))
if not self.match(","): if not self.match(","):
@ -865,7 +857,8 @@ proc parsePragmas(self: Parser): seq[Pragma] =
self.expect(LeftParen, "unterminated parenthesis in pragma arguments") self.expect(LeftParen, "unterminated parenthesis in pragma arguments")
else: else:
exp = self.primary() exp = self.primary()
if not exp.isLiteral(): if exp.kind notin {strExpr, intExpr, octExpr, binExpr, hexExpr, floatExpr,
trueExpr, falseExpr}:
self.error("pragma arguments can only be literals", exp.token) self.error("pragma arguments can only be literals", exp.token)
args.add(LiteralExpr(exp)) args.add(LiteralExpr(exp))
result.add(newPragma(name, args)) result.add(newPragma(name, args))

View File

@ -9,30 +9,6 @@ fn clock*: float {
} }
fn print*(x: int) { fn print*[T: Number | string | bool | nan | inf](x: T) {
#pragma[magic: "PrintInt64"] #pragma[magic: "print"]
} }
fn print*(x: int32) {
#pragma[magic: "PrintInt32"]
}
fn print*(x: uint64) {
#pragma[magic: "PrintUInt64"]
}
fn print*(x: float) {
#pragma[magic: "PrintFloat64"]
}
fn print*(x: string) {
#pragma[magic: "PrintString"]
}
fn print*(x: bool) {
#pragma[magic: "PrintBool"]
}

View File

@ -1,23 +1,73 @@
# Stub type declarations for peon's intrinsic types # Stub type declarations for peon's intrinsic types
type int64* = object {#pragma[magic: "int64"]} type int64* = object {
type int32* = object {#pragma[magic: "int32"]} #pragma[magic: "int64"]
type int16* = object {#pragma[magic: "int16"]} }
type int8* = object {#pragma[magic: "int8"]}
type uint64* = object {#pragma[magic: "uint64"]} type int32* = object {
type uint32* = object {#pragma[magic: "uint32"]} #pragma[magic: "int32"]
type uint16* = object {#pragma[magic: "uint16"]} }
type uint8* = object {#pragma[magic: "uint8"]}
type float64* = object {#pragma[magic: "float64"]} type int16* = object {
type float32* = object {#pragma[magic: "float32"]} #pragma[magic: "int16"]
type bool* = object {#pragma[magic: "bool"]} }
type string* = object {#pragma[magic: "string"]}
type any* = object {#pragma[magic: "any"]} type int8* = object {
#pragma[magic: "int8"]
}
type uint64* = object {
#pragma[magic: "uint64"]
}
type uint32* = object {
#pragma[magic: "uint32"]
}
type uint16* = object {
#pragma[magic: "uint16"]
}
type uint8* = object {
#pragma[magic: "uint8"]
}
type float64* = object {
#pragma[magic: "float64"]
}
type float32* = object {
#pragma[magic: "float32"]
}
type bool* = object {
#pragma[magic: "bool"]
}
type string* = object {
#pragma[magic: "string"]
}
type any* = object {
#pragma[magic: "any"]
}
type inf* = object {
#pragma[magic: "inf"]
}
type nil* = object {
#pragma[magic: "nil"]
}
type nan* = object {
#pragma[magic: "nan"]
}
# Some convenience aliases # Some convenience aliases
type int* = int64; type int* = int64;
type float* = float64; type float* = float64;
type SignedInteger* = int64 | int32 | int16 | int8; type SignedInteger* = int64 | int32 | int16 | int8;
type UnsignedInteger* = uint64 | uint32 | uint16 | uint8; type UnsignedInteger* = uint64 | uint32 | uint16 | uint8;
type Integer* = SignedInteger | UnsignedInteger; type Integer* = SignedInteger | UnsignedInteger;

View File

@ -51,9 +51,6 @@ proc fillSymbolTable*(tokenizer: Lexer) =
# but we don't need to care about that until # but we don't need to care about that until
# we're in the parsing/compilation steps so # we're in the parsing/compilation steps so
# it's fine # it's fine
tokenizer.symbols.addKeyword("nan", NotANumber)
tokenizer.symbols.addKeyword("inf", Infinity)
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", TokenType.Ref) tokenizer.symbols.addKeyword("ref", TokenType.Ref)

View File

@ -19,4 +19,4 @@ fn fooBar(a, b: int): int {
noReturn(1); noReturn(1);
print(fooBar(1, 3) == 1); # true print(fooBar(1, 3) == 1); # true

View File

@ -1,4 +1,4 @@
# Another test for generic functions # A test for generic functions
import std; import std;
@ -9,4 +9,4 @@ fn sum[T: int | int32](a, b: T): T {
print(sum(1, 2)); # Prints 3 print(sum(1, 2)); # Prints 3
print(sum(1'i32, 2'i32)); # Also prints 3! print(sum(1'i32, 2'i32)); # Also prints 3!
#print(sum(1.0, 2.0)); # Will fail to compile #print(sum(1.0, 2.0)); # Will fail to compile

View File

@ -1,4 +1,6 @@
# Tests more stuff about generics. This test should fail to compile # Tests more stuff about generics. This test should fail to compile
import std;
fn identity(x: int32): int32 { fn identity(x: int32): int32 {
return x; return x;