WIP: dev #1
@@ -232,6 +232,20 @@ static inline string *string_from_cstr(char *cstr)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define da_append(xs, x) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if ((xs)->count >= (xs)->capacity) \
|
||||||
|
{ \
|
||||||
|
if ((xs)->capacity == 0) (xs)->capacity = 256; \
|
||||||
|
else (xs)->capacity *= 2; \
|
||||||
|
(xs)->items = realloc((xs)->items, (xs)->capacity*sizeof(*(xs)->items)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
(xs)->items[(xs)->count++] = (x); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -406,6 +420,9 @@ static inline string *string_from_cstr(char *cstr)
|
|||||||
case TypedNodeStatementWhile statement:
|
case TypedNodeStatementWhile statement:
|
||||||
EmitStatementWhile(statement);
|
EmitStatementWhile(statement);
|
||||||
break;
|
break;
|
||||||
|
case TypedNodeStatementFor statement:
|
||||||
|
EmitStatementFor(statement);
|
||||||
|
break;
|
||||||
case TypedNodeStatementMatch statement:
|
case TypedNodeStatementMatch statement:
|
||||||
EmitStatementMatch(statement);
|
EmitStatementMatch(statement);
|
||||||
break;
|
break;
|
||||||
@@ -514,6 +531,21 @@ static inline string *string_from_cstr(char *cstr)
|
|||||||
writer.WriteLine("}");
|
writer.WriteLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EmitStatementFor(TypedNodeStatementFor statement)
|
||||||
|
{
|
||||||
|
var index = Tmp();
|
||||||
|
var array = EmitExpression(statement.Array);
|
||||||
|
writer.WriteLine($"for (size_t {index} = 0; {index} < {array}.count; ++{index})");
|
||||||
|
writer.WriteLine("{");
|
||||||
|
using (writer.Indent())
|
||||||
|
{
|
||||||
|
var arrayType = (NubTypeArray)statement.Array.Type;
|
||||||
|
writer.WriteLine($"{CType(arrayType.ElementType, statement.VariableName.Ident)} = {array}.items[{index}];");
|
||||||
|
EmitStatement(statement.Body);
|
||||||
|
}
|
||||||
|
writer.WriteLine("}");
|
||||||
|
}
|
||||||
|
|
||||||
private void EmitStatementMatch(TypedNodeStatementMatch statement)
|
private void EmitStatementMatch(TypedNodeStatementMatch statement)
|
||||||
{
|
{
|
||||||
var target = EmitExpression(statement.Target);
|
var target = EmitExpression(statement.Target);
|
||||||
@@ -565,6 +597,7 @@ static inline string *string_from_cstr(char *cstr)
|
|||||||
TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
|
TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
|
||||||
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
||||||
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression),
|
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression),
|
||||||
|
TypedNodeExpressionArrayLiteral expression => EmitNodeExpressionArrayLiteral(expression),
|
||||||
TypedNodeExpressionStringConstructor expression => EmitExpressionStringConstructor(expression),
|
TypedNodeExpressionStringConstructor expression => EmitExpressionStringConstructor(expression),
|
||||||
TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression),
|
TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression),
|
||||||
TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression),
|
TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression),
|
||||||
@@ -588,7 +621,7 @@ static inline string *string_from_cstr(char *cstr)
|
|||||||
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)
|
||||||
{
|
{
|
||||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||||
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = nub_core_string_concat({left}, {right});");
|
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = string_concat({left}, {right});");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,12 +726,27 @@ static inline string *string_from_cstr(char *cstr)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string EmitNodeExpressionArrayLiteral(TypedNodeExpressionArrayLiteral expression)
|
||||||
|
{
|
||||||
|
var name = Tmp();
|
||||||
|
|
||||||
|
writer.WriteLine($"{CType(expression.Type, name)} = {{0}};");
|
||||||
|
|
||||||
|
foreach (var value in expression.Values)
|
||||||
|
{
|
||||||
|
var valueName = EmitExpression(value);
|
||||||
|
writer.WriteLine($"da_append(&{name}, {valueName});");
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
private string EmitExpressionStringConstructor(TypedNodeExpressionStringConstructor expression)
|
private string EmitExpressionStringConstructor(TypedNodeExpressionStringConstructor expression)
|
||||||
{
|
{
|
||||||
var name = Tmp();
|
var name = Tmp();
|
||||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||||
var value = EmitExpression(expression.Value);
|
var value = EmitExpression(expression.Value);
|
||||||
writer.WriteLine($"{CType(expression.Type, name)} = nub_core_string_from_cstr({value});");
|
writer.WriteLine($"{CType(expression.Type, name)} = string_from_cstr({value});");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -263,8 +263,17 @@ public class Parser
|
|||||||
if (TryExpectKeyword(Keyword.While))
|
if (TryExpectKeyword(Keyword.While))
|
||||||
{
|
{
|
||||||
var condition = ParseExpression();
|
var condition = ParseExpression();
|
||||||
var thenBlock = ParseStatement();
|
var block = ParseStatement();
|
||||||
return new NodeStatementWhile(TokensFrom(startIndex), condition, thenBlock);
|
return new NodeStatementWhile(TokensFrom(startIndex), condition, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryExpectKeyword(Keyword.For))
|
||||||
|
{
|
||||||
|
var variableName = ExpectIdent();
|
||||||
|
ExpectKeyword(Keyword.In);
|
||||||
|
var array = ParseExpression();
|
||||||
|
var block = ParseStatement();
|
||||||
|
return new NodeStatementFor(TokensFrom(startIndex), variableName, array, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryExpectKeyword(Keyword.Match))
|
if (TryExpectKeyword(Keyword.Match))
|
||||||
@@ -363,6 +372,19 @@ public class Parser
|
|||||||
var target = ParseExpression();
|
var target = ParseExpression();
|
||||||
expr = new NodeExpressionUnary(TokensFrom(startIndex), target, NodeExpressionUnary.Op.Negate);
|
expr = new NodeExpressionUnary(TokensFrom(startIndex), target, NodeExpressionUnary.Op.Negate);
|
||||||
}
|
}
|
||||||
|
else if (TryExpectSymbol(Symbol.OpenSquare))
|
||||||
|
{
|
||||||
|
var values = new List<NodeExpression>();
|
||||||
|
|
||||||
|
while (!TryExpectSymbol(Symbol.CloseSquare))
|
||||||
|
{
|
||||||
|
var value = ParseExpression();
|
||||||
|
values.Add(value);
|
||||||
|
TryExpectSymbol(Symbol.Comma);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr = new NodeExpressionArrayLiteral(TokensFrom(startIndex), values);
|
||||||
|
}
|
||||||
else if (TryExpectSymbol(Symbol.OpenCurly))
|
else if (TryExpectSymbol(Symbol.OpenCurly))
|
||||||
{
|
{
|
||||||
var initializers = new List<NodeExpressionStructLiteral.Initializer>();
|
var initializers = new List<NodeExpressionStructLiteral.Initializer>();
|
||||||
@@ -893,6 +915,13 @@ public class NodeStatementWhile(List<Token> tokens, NodeExpression condition, No
|
|||||||
public NodeStatement Body { get; } = body;
|
public NodeStatement Body { get; } = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NodeStatementFor(List<Token> tokens, TokenIdent variableName, NodeExpression array, NodeStatement body) : NodeStatement(tokens)
|
||||||
|
{
|
||||||
|
public TokenIdent VariableName { get; } = variableName;
|
||||||
|
public NodeExpression Array { get; } = array;
|
||||||
|
public NodeStatement Body { get; } = body;
|
||||||
|
}
|
||||||
|
|
||||||
public class NodeStatementMatch(List<Token> tokens, NodeExpression target, List<NodeStatementMatch.Case> cases) : NodeStatement(tokens)
|
public class NodeStatementMatch(List<Token> tokens, NodeExpression target, List<NodeStatementMatch.Case> cases) : NodeStatement(tokens)
|
||||||
{
|
{
|
||||||
public NodeExpression Target { get; } = target;
|
public NodeExpression Target { get; } = target;
|
||||||
@@ -941,6 +970,11 @@ public class NodeExpressionEnumLiteral(List<Token> tokens, NodeTypeNamed type, N
|
|||||||
public NodeExpression? Value { get; } = value;
|
public NodeExpression? Value { get; } = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NodeExpressionArrayLiteral(List<Token> tokens, List<NodeExpression> values) : NodeExpression(tokens)
|
||||||
|
{
|
||||||
|
public List<NodeExpression> Values { get; } = values;
|
||||||
|
}
|
||||||
|
|
||||||
public class NodeExpressionStringConstructor(List<Token> tokens, NodeExpression value) : NodeExpression(tokens)
|
public class NodeExpressionStringConstructor(List<Token> tokens, NodeExpression value) : NodeExpression(tokens)
|
||||||
{
|
{
|
||||||
public NodeExpression Value { get; } = value;
|
public NodeExpression Value { get; } = value;
|
||||||
|
|||||||
@@ -405,6 +405,8 @@ public class Tokenizer
|
|||||||
"if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If),
|
"if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If),
|
||||||
"else" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Else),
|
"else" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Else),
|
||||||
"while" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.While),
|
"while" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.While),
|
||||||
|
"for" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.For),
|
||||||
|
"in" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.In),
|
||||||
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
|
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
|
||||||
"module" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Module),
|
"module" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Module),
|
||||||
"export" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Export),
|
"export" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Export),
|
||||||
@@ -557,6 +559,8 @@ public enum Keyword
|
|||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
While,
|
While,
|
||||||
|
For,
|
||||||
|
In,
|
||||||
Return,
|
Return,
|
||||||
Module,
|
Module,
|
||||||
Export,
|
Export,
|
||||||
@@ -627,6 +631,8 @@ public static class TokenExtensions
|
|||||||
Keyword.If => "if",
|
Keyword.If => "if",
|
||||||
Keyword.Else => "else",
|
Keyword.Else => "else",
|
||||||
Keyword.While => "while",
|
Keyword.While => "while",
|
||||||
|
Keyword.For => "for",
|
||||||
|
Keyword.In => "in",
|
||||||
Keyword.Return => "return",
|
Keyword.Return => "return",
|
||||||
Keyword.Module => "module",
|
Keyword.Module => "module",
|
||||||
Keyword.Export => "export",
|
Keyword.Export => "export",
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ public class TypeChecker
|
|||||||
NodeStatementReturn statement => CheckStatementReturn(statement),
|
NodeStatementReturn statement => CheckStatementReturn(statement),
|
||||||
NodeStatementVariableDeclaration statement => CheckStatementVariableDeclaration(statement),
|
NodeStatementVariableDeclaration statement => CheckStatementVariableDeclaration(statement),
|
||||||
NodeStatementWhile statement => CheckStatementWhile(statement),
|
NodeStatementWhile statement => CheckStatementWhile(statement),
|
||||||
|
NodeStatementFor statement => CheckStatementFor(statement),
|
||||||
NodeStatementMatch statement => CheckStatementMatch(statement),
|
NodeStatementMatch statement => CheckStatementMatch(statement),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||||
};
|
};
|
||||||
@@ -204,6 +205,22 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TypedNodeStatementFor CheckStatementFor(NodeStatementFor statement)
|
||||||
|
{
|
||||||
|
var array = CheckExpression(statement.Array, null);
|
||||||
|
if (array.Type is not NubTypeArray arrayType)
|
||||||
|
throw BasicError($"Cannot iterate over non-array type '{array.Type}'", statement.Array);
|
||||||
|
|
||||||
|
TypedNodeStatement body;
|
||||||
|
using (EnterScope())
|
||||||
|
{
|
||||||
|
DeclareLocalIdentifier(statement.VariableName, arrayType.ElementType);
|
||||||
|
body = CheckStatement(statement.Body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TypedNodeStatementFor(statement.Tokens, statement.VariableName, array, body);
|
||||||
|
}
|
||||||
|
|
||||||
private TypedNodeStatementMatch CheckStatementMatch(NodeStatementMatch statement)
|
private TypedNodeStatementMatch CheckStatementMatch(NodeStatementMatch statement)
|
||||||
{
|
{
|
||||||
var target = CheckExpression(statement.Target, null);
|
var target = CheckExpression(statement.Target, null);
|
||||||
@@ -264,6 +281,7 @@ public class TypeChecker
|
|||||||
NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType),
|
NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType),
|
||||||
NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType),
|
NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType),
|
||||||
NodeExpressionStringConstructor expression => CheckExpressionStringConstructor(expression, expectedType),
|
NodeExpressionStringConstructor expression => CheckExpressionStringConstructor(expression, expectedType),
|
||||||
|
NodeExpressionArrayLiteral expression => CheckExpressionArrayLiteral(expression, expectedType),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -675,6 +693,31 @@ public class TypeChecker
|
|||||||
return new TypedNodeExpressionStringConstructor(expression.Tokens, NubTypeString.Instance, value);
|
return new TypedNodeExpressionStringConstructor(expression.Tokens, NubTypeString.Instance, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TypedNodeExpressionArrayLiteral CheckExpressionArrayLiteral(NodeExpressionArrayLiteral expression, NubType? expectedType)
|
||||||
|
{
|
||||||
|
NubType? elementType = null;
|
||||||
|
if (expectedType is NubTypeArray arrayType)
|
||||||
|
elementType = arrayType.ElementType;
|
||||||
|
|
||||||
|
var values = new List<TypedNodeExpression>();
|
||||||
|
|
||||||
|
foreach (var value in expression.Values)
|
||||||
|
{
|
||||||
|
var checkedValue = CheckExpression(value, elementType);
|
||||||
|
elementType ??= checkedValue.Type;
|
||||||
|
|
||||||
|
if (!checkedValue.Type.IsAssignableTo(elementType))
|
||||||
|
throw BasicError($"Type '{checkedValue.Type}' is not assignable to type of element '{elementType}'", checkedValue);
|
||||||
|
|
||||||
|
values.Add(checkedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementType is null)
|
||||||
|
throw BasicError("Unable to infer type of array element", expression);
|
||||||
|
|
||||||
|
return new TypedNodeExpressionArrayLiteral(expression.Tokens, NubTypeArray.Get(elementType), values);
|
||||||
|
}
|
||||||
|
|
||||||
private NubType ResolveType(NodeType node)
|
private NubType ResolveType(NodeType node)
|
||||||
{
|
{
|
||||||
return node switch
|
return node switch
|
||||||
@@ -908,6 +951,13 @@ public class TypedNodeStatementWhile(List<Token> tokens, TypedNodeExpression con
|
|||||||
public TypedNodeStatement Body { get; } = body;
|
public TypedNodeStatement Body { get; } = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TypedNodeStatementFor(List<Token> tokens, TokenIdent variableName, TypedNodeExpression array, TypedNodeStatement body) : TypedNodeStatement(tokens)
|
||||||
|
{
|
||||||
|
public TokenIdent VariableName { get; } = variableName;
|
||||||
|
public TypedNodeExpression Array { get; } = array;
|
||||||
|
public TypedNodeStatement Body { get; } = body;
|
||||||
|
}
|
||||||
|
|
||||||
public class TypedNodeStatementMatch(List<Token> tokens, TypedNodeExpression target, List<TypedNodeStatementMatch.Case> cases) : TypedNodeStatement(tokens)
|
public class TypedNodeStatementMatch(List<Token> tokens, TypedNodeExpression target, List<TypedNodeStatementMatch.Case> cases) : TypedNodeStatement(tokens)
|
||||||
{
|
{
|
||||||
public TypedNodeExpression Target { get; } = target;
|
public TypedNodeExpression Target { get; } = target;
|
||||||
@@ -962,6 +1012,11 @@ public class TypedNodeExpressionStringConstructor(List<Token> tokens, NubType ty
|
|||||||
public TypedNodeExpression Value { get; } = value;
|
public TypedNodeExpression Value { get; } = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TypedNodeExpressionArrayLiteral(List<Token> tokens, NubType type, List<TypedNodeExpression> values) : TypedNodeExpression(tokens, type)
|
||||||
|
{
|
||||||
|
public List<TypedNodeExpression> Values { get; } = values;
|
||||||
|
}
|
||||||
|
|
||||||
public class TypedNodeExpressionStructMemberAccess(List<Token> tokens, NubType type, TypedNodeExpression target, TokenIdent name) : TypedNodeExpression(tokens, type)
|
public class TypedNodeExpressionStructMemberAccess(List<Token> tokens, NubType type, TypedNodeExpression target, TokenIdent name) : TypedNodeExpression(tokens, type)
|
||||||
{
|
{
|
||||||
public TypedNodeExpression Target { get; } = target;
|
public TypedNodeExpression Target { get; } = target;
|
||||||
|
|||||||
@@ -11,18 +11,11 @@ enum Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main(): i32 {
|
func main(): i32 {
|
||||||
let message = getMessage()
|
let names = ["a", "b", "c", "d"]
|
||||||
|
|
||||||
match message {
|
for name in names {
|
||||||
Quit {}
|
core::println(name)
|
||||||
Say msg {
|
|
||||||
core::println(msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMessage(): Message {
|
|
||||||
return new Message::Say("testæøå")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user