Fixed issues with generic specialization and other minor bugs
This commit is contained in:
parent
789462c86a
commit
bc0f614143
|
@ -12,7 +12,9 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import strformat
|
||||
import std/strformat
|
||||
import std/os
|
||||
|
||||
|
||||
# These variables can be tweaked to debug and test various components of the toolchain
|
||||
var debugLexer* = false # Print the tokenizer's output
|
||||
|
@ -30,7 +32,7 @@ const HeapGrowFactor* = 2 # The growth factor used by the G
|
|||
const FirstGC* = 1024 * 1024; # How many bytes to allocate before running the first GC
|
||||
const enableVMChecks* {.booldefine.} = true; # Enables all types of compiler (nim-wise) checks in the VM
|
||||
# List of paths where peon looks for modules, in order (empty path means current directory, which always takes precedence)
|
||||
const moduleLookupPaths*: seq[string] = @["", "src/peon/stdlib", "/home/nocturn9x/.local/peon/stdlib"]
|
||||
const moduleLookupPaths*: seq[string] = @["", "src/peon/stdlib", absolutePath(joinPath(".local", "peon", "stdlib"), getenv("HOME"))]
|
||||
when HeapGrowFactor <= 1:
|
||||
{.fatal: "Heap growth factor must be > 1".}
|
||||
const PeonVersion* = (major: 0, minor: 1, patch: 0)
|
||||
|
|
|
@ -100,6 +100,9 @@ type
|
|||
case kind*: NameKind
|
||||
of NameKind.Module:
|
||||
path*: string
|
||||
# Full absolute path of the module,
|
||||
# including the extension
|
||||
absPath*: string
|
||||
else:
|
||||
discard
|
||||
# The name's identifier
|
||||
|
@ -134,7 +137,7 @@ type
|
|||
node*: Declaration
|
||||
# Who is this name exported to? (Only makes sense if isPrivate
|
||||
# equals false)
|
||||
exportedTo*: HashSet[string]
|
||||
exportedTo*: seq[Name]
|
||||
# Has the compiler generated this name internally or
|
||||
# does it come from user code?
|
||||
isReal*: bool
|
||||
|
@ -346,7 +349,7 @@ proc resolve*(self: Compiler, name: string): Name =
|
|||
## Returns nil when the name can't be found
|
||||
for obj in reversed(self.names):
|
||||
if obj.ident.token.lexeme == name:
|
||||
if obj.owner.path != self.currentModule.path:
|
||||
if obj.owner.absPath != self.currentModule.absPath:
|
||||
# We don't own this name, but we
|
||||
# may still have access to it
|
||||
if obj.isPrivate:
|
||||
|
@ -354,7 +357,7 @@ proc resolve*(self: Compiler, name: string): Name =
|
|||
# module, so we definitely can't
|
||||
# use it
|
||||
continue
|
||||
if self.currentModule.path in obj.exportedTo:
|
||||
if self.currentModule in obj.exportedTo:
|
||||
# The name is public in its owner
|
||||
# module and said module has explicitly
|
||||
# exported it to us: we can use it
|
||||
|
@ -712,8 +715,8 @@ method findByName*(self: Compiler, name: string): seq[Name] =
|
|||
## with the given name. Returns all objects that apply.
|
||||
for obj in reversed(self.names):
|
||||
if obj.ident.token.lexeme == name:
|
||||
if obj.owner.path != self.currentModule.path:
|
||||
if obj.isPrivate or self.currentModule.path notin obj.exportedTo:
|
||||
if obj.owner.absPath != self.currentModule.absPath:
|
||||
if obj.isPrivate or self.currentModule notin obj.exportedTo:
|
||||
continue
|
||||
result.add(obj)
|
||||
|
||||
|
@ -729,11 +732,11 @@ method findInModule*(self: Compiler, name: string, module: Name): seq[Name] =
|
|||
for obj in reversed(self.names):
|
||||
if obj.owner.isNil():
|
||||
continue
|
||||
if not obj.isPrivate and obj.owner.path == module.path:
|
||||
if not obj.isPrivate and obj.owner.absPath == module.absPath:
|
||||
result.add(obj)
|
||||
else:
|
||||
for obj in self.findInModule("", module):
|
||||
if obj.ident.token.lexeme == name and self.currentModule.path in obj.exportedTo:
|
||||
if obj.ident.token.lexeme == name and self.currentModule in obj.exportedTo:
|
||||
result.add(obj)
|
||||
|
||||
|
||||
|
@ -1036,7 +1039,7 @@ proc declare*(self: Compiler, node: ASTNode): Name {.discardable.} =
|
|||
break
|
||||
if name.ident.token.lexeme != declaredName:
|
||||
continue
|
||||
if name.owner != n.owner and (name.isPrivate or n.owner.path notin name.exportedTo):
|
||||
if name.owner != n.owner and (name.isPrivate or n.owner notin name.exportedTo):
|
||||
continue
|
||||
if name.kind in [NameKind.Var, NameKind.Module, NameKind.CustomType, NameKind.Enum]:
|
||||
if name.depth < n.depth:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1172,9 +1172,13 @@ method unary(self: BytecodeCompiler, node: UnaryExpr, compile: bool = true): Typ
|
|||
returnType: Type(kind: Any),
|
||||
args: @[("", self.inferOrError(node.a), default)])
|
||||
var impl = self.match(node.token.lexeme, fn, node)
|
||||
if impl.valueType.isAuto:
|
||||
result = impl.valueType
|
||||
if impl.isGeneric:
|
||||
result = self.specialize(impl.valueType, @[node.a])
|
||||
elif impl.valueType.isAuto:
|
||||
impl = self.prepareAutoFunction(impl, fn.args)
|
||||
result = impl.valueType.returnType
|
||||
result = impl.valueType
|
||||
result = result.returnType
|
||||
if compile:
|
||||
self.generateCall(impl, @[node.a], impl.line)
|
||||
|
||||
|
@ -1184,9 +1188,13 @@ method binary(self: BytecodeCompiler, node: BinaryExpr, compile: bool = true): T
|
|||
var default: Expression
|
||||
let fn = Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.inferOrError(node.a), default), ("", self.inferOrError(node.b), default)])
|
||||
var impl = self.match(node.token.lexeme, fn, node)
|
||||
if impl.valueType.isAuto:
|
||||
result = impl.valueType
|
||||
if impl.isGeneric:
|
||||
result = self.specialize(impl.valueType, @[node.a, node.b])
|
||||
elif impl.valueType.isAuto:
|
||||
impl = self.prepareAutoFunction(impl, fn.args)
|
||||
result = impl.valueType.returnType
|
||||
result = impl.valueType
|
||||
result = result.returnType
|
||||
if compile:
|
||||
self.generateCall(impl, @[node.a, node.b], impl.line)
|
||||
|
||||
|
@ -1305,7 +1313,9 @@ method call(self: BytecodeCompiler, node: CallExpr, compile: bool = true): Type
|
|||
# Calls like hi()
|
||||
var impl = self.match(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: All), args: args), node)
|
||||
result = impl.valueType
|
||||
if impl.valueType.isAuto:
|
||||
if impl.isGeneric:
|
||||
result = self.specialize(impl.valueType, argExpr)
|
||||
elif impl.valueType.isAuto:
|
||||
impl = self.prepareAutoFunction(impl, args)
|
||||
result = impl.valueType
|
||||
if result.fun.kind == NodeKind.lambdaExpr:
|
||||
|
@ -1350,13 +1360,20 @@ method call(self: BytecodeCompiler, node: CallExpr, compile: bool = true): Type
|
|||
result = result.returnType
|
||||
of NodeKind.getItemExpr:
|
||||
var node = GetItemExpr(node.callee)
|
||||
let impl = self.getItemExpr(node, compile=false, matching=Type(kind: Function, args: args, returnType: Type(kind: All)))
|
||||
result = self.getItemExpr(node, compile=false, matching=Type(kind: Function, args: args, returnType: Type(kind: All)))
|
||||
var fn: Name
|
||||
# getItemExpr returns a Type object, but
|
||||
# we need a Name object!
|
||||
for name in self.names:
|
||||
if name.valueType == impl:
|
||||
if name.valueType == result:
|
||||
fn = name
|
||||
break
|
||||
result = impl.returnType
|
||||
if fn.isGeneric:
|
||||
result = self.specialize(result, argExpr)
|
||||
elif result.isAuto:
|
||||
fn = self.prepareAutoFunction(fn, args)
|
||||
result = fn.valueType
|
||||
result = result.returnType
|
||||
if compile:
|
||||
self.generateCall(fn, argExpr, node.token.line)
|
||||
of NodeKind.lambdaExpr:
|
||||
|
@ -1393,7 +1410,7 @@ method getItemExpr(self: BytecodeCompiler, node: GetItemExpr, compile: bool = tr
|
|||
for name in values:
|
||||
if self.compare(name.valueType, matching):
|
||||
result = name.valueType
|
||||
break
|
||||
return
|
||||
if len(values) == 1:
|
||||
result = values[0].valueType
|
||||
else:
|
||||
|
@ -1687,14 +1704,14 @@ proc importStmt(self: BytecodeCompiler, node: ImportStmt, compile: bool = true)
|
|||
# Importing a module automatically exports
|
||||
# its public names to us
|
||||
for name in self.findInModule("", module):
|
||||
name.exportedTo.incl(self.currentModule.path)
|
||||
name.exportedTo.add(self.currentModule)
|
||||
# We also need to export public names from other modules
|
||||
# that we have explicitly exported because imports are
|
||||
# compiled only once
|
||||
for module in self.modules.values():
|
||||
if self.currentModule.path in module.exportedTo:
|
||||
if self.currentModule in module.exportedTo:
|
||||
for name in self.findInModule("", module):
|
||||
name.exportedTo.incl(self.currentModule.path)
|
||||
name.exportedTo.add(self.currentModule)
|
||||
except IOError:
|
||||
self.error(&"could not import '{module.ident.token.lexeme}': {getCurrentExceptionMsg()}")
|
||||
except OSError:
|
||||
|
@ -1712,20 +1729,20 @@ proc exportStmt(self: BytecodeCompiler, node: ExportStmt, compile: bool = true)
|
|||
var name = self.resolveOrError(node.name)
|
||||
if name.isPrivate:
|
||||
self.error("cannot export private names")
|
||||
name.exportedTo.incl(self.parentModule.path)
|
||||
name.exportedTo.add(self.parentModule)
|
||||
case name.kind:
|
||||
of NameKind.Module:
|
||||
# We need to export everything
|
||||
# this module defines!
|
||||
for name in self.findInModule("", name):
|
||||
name.exportedTo.incl(self.parentModule.path)
|
||||
name.exportedTo.add(self.parentModule)
|
||||
of NameKind.Function:
|
||||
# Only exporting a single function (or, well
|
||||
# all of its implementations)
|
||||
for name in self.findByName(name.ident.token.lexeme):
|
||||
if name.kind != NameKind.Function:
|
||||
continue
|
||||
name.exportedTo.incl(self.parentModule.path)
|
||||
name.exportedTo.add(self.parentModule)
|
||||
else:
|
||||
self.error("unsupported export type")
|
||||
|
||||
|
@ -2097,19 +2114,28 @@ proc compileModule(self: BytecodeCompiler, module: Name) =
|
|||
## Compiles an imported module into an existing chunk
|
||||
## using the compiler's internal parser and lexer objects
|
||||
var path = ""
|
||||
var moduleName = module.path & ".pn"
|
||||
let moduleName = module.path & ".pn"
|
||||
# We take the absolute path of the module so that we
|
||||
# know that if it's in self.modules, then we already
|
||||
# imported it
|
||||
for i, searchPath in moduleLookupPaths:
|
||||
if searchPath == "":
|
||||
path = absolutePath(joinPath(splitPath(self.file).head, moduleName))
|
||||
else:
|
||||
path = joinPath(searchPath, moduleName)
|
||||
path = absolutePath(joinPath(searchPath, moduleName))
|
||||
if fileExists(path):
|
||||
break
|
||||
elif i == searchPath.high():
|
||||
self.error(&"""could not import '{path}': module not found""")
|
||||
if self.modules.hasKey(module.path):
|
||||
module.absPath = path
|
||||
if self.modules.hasKey(path):
|
||||
# Module is already imported: we have
|
||||
# already compiled it
|
||||
return
|
||||
let source = readFile(path)
|
||||
# Preserve the current state so we can
|
||||
# resume compiling the current module
|
||||
# later
|
||||
let current = self.current
|
||||
let ast = self.ast
|
||||
let file = self.file
|
||||
|
@ -2120,15 +2146,23 @@ proc compileModule(self: BytecodeCompiler, module: Name) =
|
|||
let parentModule = self.parentModule
|
||||
let replMode = self.replMode
|
||||
self.replMode = false
|
||||
# Set the current module to the new module
|
||||
# and the current module as the parent module:
|
||||
# this is needed for export statements
|
||||
self.parentModule = currentModule
|
||||
self.currentModule = module
|
||||
# We remember where the new module starts, but
|
||||
# we don't emit the bytes into the chunk right
|
||||
# away because we may call this function again
|
||||
# from within this call and it would break all
|
||||
# sorts of things
|
||||
let start = self.chunk.code.len()
|
||||
discard self.compile(self.parser.parse(self.lexer.lex(source, path),
|
||||
path, self.lexer.getLines(),
|
||||
self.lexer.getSource(), persist=true),
|
||||
path, self.lexer.getLines(), self.lexer.getSource(), chunk=self.chunk, incremental=true,
|
||||
isMainModule=false, self.disabledWarnings, self.showMismatches, self.mode)
|
||||
# Mark the end of a new module
|
||||
# Mark the boundaries of the module
|
||||
self.chunk.modules.extend(start.toTriple())
|
||||
self.chunk.modules.extend(self.chunk.code.high().toTriple())
|
||||
# I swear to god if someone ever creates a peon module with a name that's
|
||||
|
@ -2148,4 +2182,4 @@ proc compileModule(self: BytecodeCompiler, module: Name) =
|
|||
self.replMode = replMode
|
||||
self.lines = lines
|
||||
self.source = src
|
||||
self.modules[module.path] = module
|
||||
self.modules[module.absPath] = module
|
||||
|
|
Loading…
Reference in New Issue