Skip to content

Commit

Permalink
Merge pull request #240 from vein-lang/improvements/compiler-features
Browse files Browse the repository at this point in the history
for loop support and other improvements
  • Loading branch information
0xF6 authored Jun 15, 2024
2 parents fde1ac3 + 2518083 commit cb579d0
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 26 deletions.
24 changes: 23 additions & 1 deletion lib/ast/syntax/Statement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,17 @@ from decl in local_variable_declarator.Positioned().Token()
select decl;

protected internal virtual Parser<StatementSyntax> declarationStatement =>
local_variable_declaration.Token().Positioned().Then(x => Parse.Char(';').Token().Return(x));
from loc in local_variable_declaration.Token().Positioned()
from s in Parse.Char(';').Token().Optional()
select ValidateSemicolon(s, loc);

protected internal virtual T ValidateSemicolon<T>(IOption<char> semi, T other) where T : BaseSyntax
{
if (semi.IsDefined)
return other;
var poz = other.Transform.pos;
throw new VeinParseException("Semicolon required", poz, other);
}

protected internal virtual Parser<StatementSyntax> foreach_statement =>
from k in KeywordExpression("foreach").Positioned().Token()
Expand All @@ -44,6 +53,18 @@ from cb in Parse.Char(')').Token()
from statement in embedded_statement.Token().Positioned()
select new ForeachStatementSyntax(declaration, exp, statement);

protected internal virtual Parser<StatementSyntax> for_statement =>
from k in KeywordExpression("for").Positioned().Token()
from ob in Parse.Char('(').Token()
from loopVariable in local_variable_declaration.Positioned().Token().Optional()
from d1 in Parse.Char(';').Token()
from exp in QualifiedExpression.Positioned().Token().Optional()
from d2 in Parse.Char(';').Token()
from loopCounter in QualifiedExpression.Positioned().Token().Optional()
from cb in Parse.Char(')').Token()
from statement in embedded_statement.Token().Positioned()
select new ForStatementSyntax(loopVariable, exp, loopCounter, statement);

protected internal virtual Parser<StatementSyntax> embedded_statement =>
Block.Or(simple_embedded_statement);

Expand All @@ -54,6 +75,7 @@ from statement in embedded_statement.Token().Positioned()
.Or(WhileStatement.Positioned())
.Or(TryStatement.Positioned())
.Or(ReturnStatement.Positioned())
.Or(for_statement.Positioned())
.Or(foreach_statement.Positioned())
.Or(FailStatement.Positioned())
.Or(DeleteStatement.Positioned());
Expand Down
28 changes: 28 additions & 0 deletions lib/ast/syntax/ast/ForStatementSyntax.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace vein.syntax;

using Sprache;

public class ForStatementSyntax(
IOption<LocalVariableDeclaration> loopVariable,
IOption<ExpressionSyntax> loopContact,
IOption<ExpressionSyntax> loopCounter,
StatementSyntax statement)
: StatementSyntax, IPositionAware<ForStatementSyntax>
{
public LocalVariableDeclaration? LoopVariable { get; } = loopVariable.GetOrDefault();
public ExpressionSyntax? LoopContact { get; } = loopContact.GetOrDefault();
public ExpressionSyntax? LoopCounter { get; } = loopCounter.GetOrDefault();
public StatementSyntax Statement { get; } = statement;


public override SyntaxType Kind => SyntaxType.ForEachStatement;

public override IEnumerable<BaseSyntax> ChildNodes
=> new BaseSyntax[] { LoopVariable!, LoopContact!, LoopCounter!, Statement }.Where(x => x is not null).ToList();

public new ForStatementSyntax SetPos(Position startPos, int length)
{
base.SetPos(startPos, length);
return this;
}
}
40 changes: 18 additions & 22 deletions lib/ast/syntax/ast/ForeachStatementSyntax.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
namespace vein.syntax
{
using System.Collections.Generic;
using Sprache;
namespace vein.syntax;

public class ForeachStatementSyntax : StatementSyntax, IPositionAware<ForeachStatementSyntax>
{
public LocalVariableDeclaration Variable { get; }
public ExpressionSyntax Expression { get; }
public StatementSyntax Statement { get; }
using System.Collections.Generic;
using Sprache;

public class ForeachStatementSyntax(
LocalVariableDeclaration declaration,
ExpressionSyntax exp,
StatementSyntax statement)
: StatementSyntax, IPositionAware<ForeachStatementSyntax>
{
public LocalVariableDeclaration Variable { get; } = declaration;
public ExpressionSyntax Expression { get; } = exp;
public StatementSyntax Statement { get; } = statement;

public override SyntaxType Kind => SyntaxType.ForEachStatement;

public override IEnumerable<BaseSyntax> ChildNodes => new List<BaseSyntax> { Variable, Expression, Statement };
public override SyntaxType Kind => SyntaxType.ForEachStatement;

public ForeachStatementSyntax(LocalVariableDeclaration declaration, ExpressionSyntax exp, StatementSyntax statement)
{
Variable = declaration;
Expression = exp;
Statement = statement;
}
public override IEnumerable<BaseSyntax> ChildNodes => new List<BaseSyntax> { Variable, Expression, Statement };

public new ForeachStatementSyntax SetPos(Position startPos, int length)
{
base.SetPos(startPos, length);
return this;
}
public new ForeachStatementSyntax SetPos(Position startPos, int length)
{
base.SetPos(startPos, length);
return this;
}
}
4 changes: 2 additions & 2 deletions lib/ast/syntax/ast/IfStatementSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace vein.syntax;
using System.Collections.Generic;
using Sprache;

public class IfStatementSyntax(ExpressionSyntax e, StatementSyntax then, StatementSyntax @else)
public class IfStatementSyntax(ExpressionSyntax e, StatementSyntax then, StatementSyntax? @else)
: StatementSyntax, IPositionAware<IfStatementSyntax>
{
public override SyntaxType Kind => SyntaxType.IfStatement;
Expand All @@ -14,7 +14,7 @@ public class IfStatementSyntax(ExpressionSyntax e, StatementSyntax then, Stateme

public StatementSyntax ThenStatement { get; set; } = then;

public StatementSyntax ElseStatement { get; set; } = @else;
public StatementSyntax? ElseStatement { get; set; } = @else;

public new IfStatementSyntax SetPos(Position startPos, int length)
{
Expand Down
2 changes: 1 addition & 1 deletion lib/ast/syntax/ast/LocalVariableDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace vein.syntax
{
using Sprache;

public class LocalVariableDeclaration : StatementSyntax, IPositionAware<LocalVariableDeclaration>
public class LocalVariableDeclaration : StatementSyntax, IAdvancedPositionAware<LocalVariableDeclaration>
{
public readonly IdentifierExpression Identifier;
public readonly IOption<ExpressionSyntax> Body;
Expand Down
2 changes: 2 additions & 0 deletions lib/ast/vein.ast.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<AssemblyName>vein.ast</AssemblyName>
<RootNamespace>vein.ast</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="morelinq" Version="3.4.2" />
Expand Down
28 changes: 28 additions & 0 deletions runtime/ishtar.generator/generators/cycles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,34 @@ public static void EmitWhileStatement(this ILGenerator gen, WhileStatementSyntax
gen.UseLabel(end);
}

public static void EmitForStatement(this ILGenerator gen, ForStatementSyntax @for)
{
var ctx = gen.ConsumeFromMetadata<GeneratorContext>("context");
if (@for.LoopVariable is not null)
gen.EmitLocalVariable(@for.LoopVariable);
var start = gen.DefineLabel("for-start");
gen.UseLabel(start);
gen.EmitStatement(@for.Statement);

if (@for.LoopCounter is not null)
gen.EmitExpression(@for.LoopCounter);
if (@for.LoopContact is not null)
{
var expType = @for.LoopContact.DetermineType(ctx);

if (expType.TypeCode is not VeinTypeCode.TYPE_BOOLEAN)
{
ctx.LogError($"Cannot implicitly convert type '{expType}' to 'Boolean'", @for.LoopContact);
return; // TODO implicit boolean
}

gen.EmitExpression(@for.LoopContact);
gen.Emit(OpCodes.JMP_T, start);
}
else
gen.Emit(OpCodes.JMP, start);
}

public static void EmitForeach(this ILGenerator generator, ForeachStatementSyntax @foreach)
{
var ctx = generator.ConsumeFromMetadata<GeneratorContext>("context");
Expand Down
2 changes: 2 additions & 0 deletions runtime/ishtar.generator/generators/logic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public static void EmitStatement(this ILGenerator generator, StatementSyntax sta
generator.EmitAccess(access);
else if (statement is WhileStatementSyntax @while)
generator.EmitWhileStatement(@while);
else if (statement is ForStatementSyntax @for)
generator.EmitForStatement(@for);
else if (statement is QualifiedExpressionStatement { Value: BinaryExpressionSyntax } qes2)
generator.EmitBinaryExpression((BinaryExpressionSyntax)qes2.Value);

Expand Down
8 changes: 8 additions & 0 deletions runtime/ishtar.generator/generators/operators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ public static ILGenerator EmitUnary(this ILGenerator gen, UnaryExpressionSyntax
gen.Emit(OpCodes.LDC_I4_0);
gen.Emit(OpCodes.EQL_NQ);
}
else if (node.OperatorType is ExpressionType.PostIncrementAssign)
{
// todo work only in for cycle, in other cases, it works like ++i
var addOne =
new BinaryExpressionSyntax(node.Operand, new Int32LiteralExpressionSyntax(1), ExpressionType.Add);
var operand_assign = new BinaryExpressionSyntax(node.Operand, addOne);
gen.EmitAssignExpression(operand_assign);
}
else
throw new NotSupportedException("EmitUnary");

Expand Down
15 changes: 15 additions & 0 deletions test/vc_test/Features/ForFeatureTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace veinc_test.Features;

public class ForFeatureTest
{
public static VeinSyntax Syntax => new();

[Test]
public void Test1() =>
Syntax.for_statement.ParseVein(
"""
for(let i = 0; i != 15; i++) {
Out.print("hello world!");
}
""");
}
128 changes: 128 additions & 0 deletions test/vc_test/Features/GenericDocumentFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
namespace veinc_test.Features;

public class GenericDocumentFeature
{
public static VeinSyntax Syntax = new();

[Test]
public void test1()
{
Syntax.CompilationUnit.ParseVein(
"""
#space "test"
#use "vein/lang"
struct App {
public test2(): void
{
for (let i = 55; i++; i != 500) {
Out.print("hello world!");
}
}
public test1(): void {
fail null;
}
public test1(): void {
let b = "asdads" + "gfdfg";
}
public static master(): void {
Out.print(Fib(15));
}
public static Fib(n: i32): i32
{
if (n < 2)
{
return n;
}
auto a = Fib(n - 1);
auto b = Fib(n - 2)
return a + b;
}
}
"""
);
}

[Test]
public void test2()
{
Syntax.CompilationUnit.ParseVein(
"""
#space "test"
#use "vein/lang"
struct App {
public test1(): i32 { return 1; }
public test2(): void { }
public test3(): boolean { return false; }
public test4(): string { return "test"; }
public test5(): void { }
public test6(): void { }
}
"""
);
}

[Test]
public void test3()
{
Syntax.CompilationUnit.ParseVein(
"""
#space "test"
#use "vein/lang"
struct App {
public test1(): i32 { fail null; }
public test2(): void { }
public test3(): boolean {
if (true) {
return true;
} else {
return false;
}
}
public test4(): string { return "test"; }
public test5(i: i32): void { }
public test6(b: string): void { }
}
"""
);
}

[Test]
public void test4()
{
Syntax.CompilationUnit.ParseVein(
"""
#space "test"
#use "vein/lang"
struct App
{
public test1(): void
{
let b = "asdads" + "gfdfg";
}
public static master(): void {
Out.print(Fib(15));
}
public static Fib(n: i32): i32
{
if (n < 2)
{
return n;
}
auto a = Fib(n - 1);
auto b = Fib(n - 2)
return a + b;
}
}
"""
);
}
}

0 comments on commit cb579d0

Please sign in to comment.