Compare commits
2 Commits
693b119781
...
0be4e35628
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0be4e35628 | ||
|
|
7dd635fa91 |
@@ -167,6 +167,9 @@ public class Generator
|
|||||||
|
|
||||||
static inline void string_rc_dec(struct nub_core_string *string)
|
static inline void string_rc_dec(struct nub_core_string *string)
|
||||||
{
|
{
|
||||||
|
if (string == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (string->flags & FLAG_STRING_LITERAL)
|
if (string->flags & FLAG_STRING_LITERAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -362,10 +365,8 @@ public class Generator
|
|||||||
if (statement.Value != null)
|
if (statement.Value != null)
|
||||||
{
|
{
|
||||||
var value = EmitExpression(statement.Value);
|
var value = EmitExpression(statement.Value);
|
||||||
var variableName = TmpName();
|
|
||||||
writer.WriteLine($"{CType(statement.Value.Type, variableName)} = {value};");
|
|
||||||
EmitCleanupAllScopes();
|
EmitCleanupAllScopes();
|
||||||
writer.WriteLine($"return {variableName};");
|
writer.WriteLine($"return {value};");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -481,7 +482,7 @@ public class Generator
|
|||||||
|
|
||||||
private string EmitExpression(TypedNodeExpression node)
|
private string EmitExpression(TypedNodeExpression node)
|
||||||
{
|
{
|
||||||
var value = node switch
|
return node switch
|
||||||
{
|
{
|
||||||
TypedNodeExpressionBinary expression => EmitExpressionBinary(expression),
|
TypedNodeExpressionBinary expression => EmitExpressionBinary(expression),
|
||||||
TypedNodeExpressionUnary expression => EmitExpressionUnary(expression),
|
TypedNodeExpressionUnary expression => EmitExpressionUnary(expression),
|
||||||
@@ -498,10 +499,6 @@ public class Generator
|
|||||||
TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression),
|
TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
||||||
};
|
};
|
||||||
|
|
||||||
var tmp = TmpName();
|
|
||||||
writer.WriteLine($"{CType(node.Type, tmp)} = {value};");
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitExpressionBinary(TypedNodeExpressionBinary expression)
|
private string EmitExpressionBinary(TypedNodeExpressionBinary expression)
|
||||||
@@ -509,15 +506,16 @@ public class Generator
|
|||||||
var left = EmitExpression(expression.Left);
|
var left = EmitExpression(expression.Left);
|
||||||
var right = EmitExpression(expression.Right);
|
var right = EmitExpression(expression.Right);
|
||||||
|
|
||||||
|
var name = Tmp();
|
||||||
|
|
||||||
if (expression.Operation == TypedNodeExpressionBinary.Op.Add && expression.Left.Type is NubTypeString && expression.Right.Type is NubTypeString)
|
if (expression.Operation == TypedNodeExpressionBinary.Op.Add && expression.Left.Type is NubTypeString && expression.Right.Type is NubTypeString)
|
||||||
{
|
{
|
||||||
var name = TmpName();
|
|
||||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||||
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = string_concat({left}, {right});");
|
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = string_concat({left}, {right});");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return expression.Operation switch
|
var op = expression.Operation switch
|
||||||
{
|
{
|
||||||
TypedNodeExpressionBinary.Op.Add => $"({left} + {right})",
|
TypedNodeExpressionBinary.Op.Add => $"({left} + {right})",
|
||||||
TypedNodeExpressionBinary.Op.Subtract => $"({left} - {right})",
|
TypedNodeExpressionBinary.Op.Subtract => $"({left} - {right})",
|
||||||
@@ -536,30 +534,40 @@ public class Generator
|
|||||||
TypedNodeExpressionBinary.Op.LogicalOr => $"({left} || {right})",
|
TypedNodeExpressionBinary.Op.LogicalOr => $"({left} || {right})",
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
writer.WriteLine($"{CType(expression.Type, name)} = {op};");
|
||||||
|
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitExpressionUnary(TypedNodeExpressionUnary expression)
|
private string EmitExpressionUnary(TypedNodeExpressionUnary expression)
|
||||||
{
|
{
|
||||||
var target = EmitExpression(expression.Target);
|
var target = EmitExpression(expression.Target);
|
||||||
|
|
||||||
return expression.Operation switch
|
var name = Tmp();
|
||||||
|
|
||||||
|
var op = expression.Operation switch
|
||||||
{
|
{
|
||||||
TypedNodeExpressionUnary.Op.Negate => $"(-{target})",
|
TypedNodeExpressionUnary.Op.Negate => $"(-{target})",
|
||||||
TypedNodeExpressionUnary.Op.Invert => $"(!{target})",
|
TypedNodeExpressionUnary.Op.Invert => $"(!{target})",
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
writer.WriteLine($"{CType(expression.Type, name)} = {op};");
|
||||||
|
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
|
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
|
||||||
{
|
{
|
||||||
var name = TmpName();
|
var name = Tmp();
|
||||||
referencedStringLiterals.Add(name, expression.Value.Value);
|
referencedStringLiterals.Add(name, expression.Value.Value);
|
||||||
return $"&{name}";
|
return $"&{name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
|
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
|
||||||
{
|
{
|
||||||
var name = TmpName();
|
var name = Tmp();
|
||||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||||
|
|
||||||
var initializerValues = new Dictionary<string, string>();
|
var initializerValues = new Dictionary<string, string>();
|
||||||
@@ -580,7 +588,7 @@ public class Generator
|
|||||||
|
|
||||||
private string EmitExpressionEnumLiteral(TypedNodeExpressionEnumLiteral expression)
|
private string EmitExpressionEnumLiteral(TypedNodeExpressionEnumLiteral expression)
|
||||||
{
|
{
|
||||||
var name = TmpName();
|
var name = Tmp();
|
||||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||||
|
|
||||||
var enumVariantType = (NubTypeEnumVariant)expression.Type;
|
var enumVariantType = (NubTypeEnumVariant)expression.Type;
|
||||||
@@ -638,7 +646,10 @@ public class Generator
|
|||||||
{
|
{
|
||||||
var name = EmitExpression(expression.Target);
|
var name = EmitExpression(expression.Target);
|
||||||
var parameterValues = expression.Parameters.Select(EmitExpression).ToList();
|
var parameterValues = expression.Parameters.Select(EmitExpression).ToList();
|
||||||
return $"{name}({string.Join(", ", parameterValues)})";
|
|
||||||
|
var tmp = Tmp();
|
||||||
|
writer.WriteLine($"{CType(expression.Type, tmp)} = {name}({string.Join(", ", parameterValues)});");
|
||||||
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CType(NubType node, string? varName = null)
|
public string CType(NubType node, string? varName = null)
|
||||||
@@ -667,7 +678,7 @@ public class Generator
|
|||||||
return $"struct {NameMangler.Mangle("anonymous", "struct", type)}{(varName != null ? $" {varName}" : "")}";
|
return $"struct {NameMangler.Mangle("anonymous", "struct", type)}{(varName != null ? $" {varName}" : "")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string TmpName()
|
private string Tmp()
|
||||||
{
|
{
|
||||||
return $"_tmp{tmpNameIndex++}";
|
return $"_tmp{tmpNameIndex++}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class TypeChecker
|
|||||||
private readonly NodeDefinitionFunc function;
|
private readonly NodeDefinitionFunc function;
|
||||||
private NubType functionReturnType = null!;
|
private NubType functionReturnType = null!;
|
||||||
private readonly ModuleGraph moduleGraph;
|
private readonly ModuleGraph moduleGraph;
|
||||||
private readonly Scope scope = new();
|
private readonly Stack<Dictionary<string, NubType>> scopes = new();
|
||||||
|
|
||||||
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,7 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (scope.EnterScope())
|
using (EnterScope())
|
||||||
{
|
{
|
||||||
foreach (var parameter in function.Parameters)
|
foreach (var parameter in function.Parameters)
|
||||||
{
|
{
|
||||||
@@ -60,6 +60,7 @@ public class TypeChecker
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
parameterType = ResolveType(parameter.Type);
|
parameterType = ResolveType(parameter.Type);
|
||||||
|
DeclareLocalIdentifier(parameter.Name, parameterType);
|
||||||
}
|
}
|
||||||
catch (CompileException e)
|
catch (CompileException e)
|
||||||
{
|
{
|
||||||
@@ -68,7 +69,6 @@ public class TypeChecker
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.DeclareIdentifier(parameter.Name.Ident, parameterType);
|
|
||||||
parameters.Add(new TypedNodeDefinitionFunc.Param(parameter.Tokens, parameter.Name, parameterType));
|
parameters.Add(new TypedNodeDefinitionFunc.Param(parameter.Tokens, parameter.Name, parameterType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ public class TypeChecker
|
|||||||
|
|
||||||
private TypedNodeStatementBlock CheckStatementBlock(NodeStatementBlock statement)
|
private TypedNodeStatementBlock CheckStatementBlock(NodeStatementBlock statement)
|
||||||
{
|
{
|
||||||
using (scope.EnterScope())
|
using (EnterScope())
|
||||||
{
|
{
|
||||||
var statements = statement.Statements.Select(CheckStatement).ToList();
|
var statements = statement.Statements.Select(CheckStatement).ToList();
|
||||||
return new TypedNodeStatementBlock(statement.Tokens, statements);
|
return new TypedNodeStatementBlock(statement.Tokens, statements);
|
||||||
@@ -137,8 +137,19 @@ public class TypeChecker
|
|||||||
if (!condition.Type.IsAssignableTo(NubTypeBool.Instance))
|
if (!condition.Type.IsAssignableTo(NubTypeBool.Instance))
|
||||||
throw BasicError("Condition part of if statement must be a boolean", condition);
|
throw BasicError("Condition part of if statement must be a boolean", condition);
|
||||||
|
|
||||||
var thenBlock = CheckStatement(statement.ThenBlock);
|
TypedNodeStatement thenBlock;
|
||||||
var elseBlock = statement.ElseBlock == null ? null : CheckStatement(statement.ElseBlock);
|
|
||||||
|
using (EnterScope())
|
||||||
|
{
|
||||||
|
thenBlock = CheckStatement(statement.ThenBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedNodeStatement? elseBlock;
|
||||||
|
|
||||||
|
using (EnterScope())
|
||||||
|
{
|
||||||
|
elseBlock = statement.ElseBlock == null ? null : CheckStatement(statement.ElseBlock);
|
||||||
|
}
|
||||||
|
|
||||||
return new TypedNodeStatementIf(statement.Tokens, condition, thenBlock, elseBlock);
|
return new TypedNodeStatementIf(statement.Tokens, condition, thenBlock, elseBlock);
|
||||||
}
|
}
|
||||||
@@ -175,7 +186,7 @@ public class TypeChecker
|
|||||||
|
|
||||||
type ??= value.Type;
|
type ??= value.Type;
|
||||||
|
|
||||||
scope.DeclareIdentifier(statement.Name.Ident, type);
|
DeclareLocalIdentifier(statement.Name, type);
|
||||||
|
|
||||||
return new TypedNodeStatementVariableDeclaration(statement.Tokens, statement.Name, type, value);
|
return new TypedNodeStatementVariableDeclaration(statement.Tokens, statement.Name, type, value);
|
||||||
}
|
}
|
||||||
@@ -186,9 +197,11 @@ public class TypeChecker
|
|||||||
if (!condition.Type.IsAssignableTo(NubTypeBool.Instance))
|
if (!condition.Type.IsAssignableTo(NubTypeBool.Instance))
|
||||||
throw BasicError("Condition part of if statement must be a boolean", condition);
|
throw BasicError("Condition part of if statement must be a boolean", condition);
|
||||||
|
|
||||||
var body = CheckStatement(statement.Body);
|
using (EnterScope())
|
||||||
|
{
|
||||||
return new TypedNodeStatementWhile(statement.Tokens, condition, body);
|
var body = CheckStatement(statement.Body);
|
||||||
|
return new TypedNodeStatementWhile(statement.Tokens, condition, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypedNodeStatementMatch CheckStatementMatch(NodeStatementMatch statement)
|
private TypedNodeStatementMatch CheckStatementMatch(NodeStatementMatch statement)
|
||||||
@@ -214,14 +227,14 @@ public class TypeChecker
|
|||||||
|
|
||||||
uncoveredCases.Remove(@case.Variant.Ident);
|
uncoveredCases.Remove(@case.Variant.Ident);
|
||||||
|
|
||||||
using (scope.EnterScope())
|
using (EnterScope())
|
||||||
{
|
{
|
||||||
if (@case.VariableName != null)
|
if (@case.VariableName != null)
|
||||||
{
|
{
|
||||||
if (variant.Type is null)
|
if (variant.Type is null)
|
||||||
throw BasicError("Cannot capture variable for enum variant without type", @case.VariableName);
|
throw BasicError("Cannot capture variable for enum variant without type", @case.VariableName);
|
||||||
|
|
||||||
scope.DeclareIdentifier(@case.VariableName.Ident, variant.Type);
|
DeclareLocalIdentifier(@case.VariableName, variant.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
var body = CheckStatement(@case.Body);
|
var body = CheckStatement(@case.Body);
|
||||||
@@ -416,14 +429,14 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
if (expression.Sections.Count == 1)
|
if (expression.Sections.Count == 1)
|
||||||
{
|
{
|
||||||
var name = expression.Sections[0].Ident;
|
var name = expression.Sections[0];
|
||||||
|
|
||||||
var localType = scope.GetIdentifierType(name);
|
var localType = GetIdentifierType(name.Ident);
|
||||||
if (localType is not null)
|
if (localType is not null)
|
||||||
return new TypedNodeExpressionLocalIdent(expression.Tokens, localType, name);
|
return new TypedNodeExpressionLocalIdent(expression.Tokens, localType, name.Ident);
|
||||||
|
|
||||||
if (moduleGraph.TryResolveIdentifier(currentModule, name, true, out var ident))
|
if (moduleGraph.TryResolveIdentifier(currentModule, name.Ident, true, out var ident))
|
||||||
return new TypedNodeExpressionGlobalIdent(expression.Tokens, ident.Type, currentModule, name);
|
return new TypedNodeExpressionGlobalIdent(expression.Tokens, ident.Type, currentModule, name.Ident);
|
||||||
}
|
}
|
||||||
else if (expression.Sections.Count == 2)
|
else if (expression.Sections.Count == 2)
|
||||||
{
|
{
|
||||||
@@ -755,45 +768,44 @@ public class TypeChecker
|
|||||||
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
|
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Scope
|
public void DeclareLocalIdentifier(TokenIdent name, NubType type)
|
||||||
{
|
{
|
||||||
private readonly Stack<Dictionary<string, NubType>> scopes = new();
|
var existing = GetIdentifierType(name.Ident);
|
||||||
|
if (existing is not null)
|
||||||
|
throw BasicError($"Local identifier '{name.Ident}' is already defined", name);
|
||||||
|
|
||||||
public IDisposable EnterScope()
|
scopes.Peek().Add(name.Ident, type);
|
||||||
{
|
}
|
||||||
scopes.Push([]);
|
|
||||||
return new ScopeGuard(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeclareIdentifier(string name, NubType type)
|
public NubType? GetIdentifierType(string name)
|
||||||
|
{
|
||||||
|
foreach (var scope in scopes)
|
||||||
{
|
{
|
||||||
scopes.Peek().Add(name, type);
|
if (scope.TryGetValue(name, out var type))
|
||||||
}
|
|
||||||
|
|
||||||
public NubType? GetIdentifierType(string name)
|
|
||||||
{
|
|
||||||
foreach (var scope in scopes)
|
|
||||||
{
|
{
|
||||||
if (scope.TryGetValue(name, out var type))
|
return type;
|
||||||
{
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExitScope()
|
return null;
|
||||||
{
|
}
|
||||||
scopes.Pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class ScopeGuard(Scope owner) : IDisposable
|
public IDisposable EnterScope()
|
||||||
|
{
|
||||||
|
scopes.Push([]);
|
||||||
|
return new ScopeGuard(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExitScope()
|
||||||
|
{
|
||||||
|
scopes.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class ScopeGuard(TypeChecker owner) : IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
{
|
{
|
||||||
public void Dispose()
|
owner.ExitScope();
|
||||||
{
|
|
||||||
owner.ExitScope();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ func main(): i32 {
|
|||||||
{
|
{
|
||||||
core::println("quit")
|
core::println("quit")
|
||||||
}
|
}
|
||||||
Say message
|
Say msg
|
||||||
{
|
{
|
||||||
core::println(message)
|
core::println(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user