Skip to content

Commit

Permalink
add ternary expression to indented while
Browse files Browse the repository at this point in the history
  • Loading branch information
b3b00 committed Nov 6, 2024
1 parent 9a79f41 commit cbdcbf4
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 10 deletions.
10 changes: 10 additions & 0 deletions src/samples/IndentedWhile/parser/IndentedWhileParserGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ public BinaryOperation BuildConcat(List<Expression> operands)

return null;
}

[Production(
"primary : QUESTION[d] IndentedWhileParserGeneric_expressions ARROW[d] IndentedWhileParserGeneric_expressions COLON[d] IndentedWhileParserGeneric_expressions")]
public WhileAST TernaryQuestion(WhileAST condition, WhileAST ifTrue, WhileAST ifFalse)
{
return new TernaryExpression(condition as Expression, ifTrue as Expression, ifFalse as Expression);
}

[Production("primary : OPEN_PAREN[d] IndentedWhileParserGeneric_expressions CLOSE_PAREN[d]")]
public WhileAST Group(WhileAST expression) => expression;

// fstrings
[Production("primary : OPEN_FSTRING[d] fstring_element* CLOSE_FSTRING[d]")]
Expand Down
39 changes: 34 additions & 5 deletions src/samples/IndentedWhile/parser/IndentedWhileTokenGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,27 @@ public enum IndentedWhileTokenGeneric

[Mode(ModeAttribute.DefaultLexerMode, "fstringExpression")]
[Lexeme(GenericToken.SugarToken, "/")] DIVIDE = 39,


[Mode("default","fstringExpression")]
[Sugar("?")]
QUESTION,

[Mode("default","fstringExpression")]
[Sugar("->")]
ARROW,

[Mode("default","fstringExpression")]
[Sugar("(")]
OPEN_PAREN,

[Mode("default","fstringExpression")]
[Sugar(")")]
CLOSE_PAREN,

[Mode("default","fstringExpression")]
[Sugar("|")]
COLON,

#endregion

#region sugar 50 ->
Expand All @@ -106,10 +126,14 @@ public enum IndentedWhileTokenGeneric

#region fstring 100 ->

[Push("fstringExpression")] [Mode("fstring")] [Sugar("{")]
[Push("fstringExpression")]
[Mode("fstring")]
[Sugar("{")]
OPEN_FSTRING_EXPPRESSION = 100,

[Pop] [Mode("fstringExpression")] [Sugar("}")]
[Pop]
[Mode("fstringExpression")]
[Sugar("}")]
CLOSE_FSTRING_EXPPRESSION = 101,

[Sugar("$\"")]
Expand All @@ -123,9 +147,14 @@ [Pop] [Mode("fstringExpression")] [Sugar("}")]
CLOSE_FSTRING,


[Mode("fstring", "fstringExpression")]
[Mode("fstring")]
[UpTo("{","\"")]
FSTRING_CONTENT
FSTRING_CONTENT,







#endregion
Expand Down
20 changes: 20 additions & 0 deletions src/samples/while/compiler/SemanticChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,26 @@ private void SemanticCheck(IfStatement ast, CompilerContext context)
SemanticCheck(ast.ElseStmt,context);
context.CloseScope();
}

private void SemanticCheck(TernaryExpression ast, CompilerContext context)
{
var val = expressionTyper.TypeExpression(ast.Condition, context);
if (val != WhileType.BOOL)
throw new SignatureException($"invalid condition type {ast.Condition.Dump("")} at {ast.Position}");
ast.CompilerScope = context.CurrentScope;

context.OpenNewScope();
var trueType = expressionTyper.TypeExpression(ast.TrueExpression, context);
context.CloseScope();

context.OpenNewScope();
var falseType = expressionTyper.TypeExpression(ast.TrueExpression, context);
context.CloseScope();
if (trueType != falseType)
{
throw new TypingException($"ternary expression at {ast.Position} has different branch types . {trueType} vis different from {falseType}");
}
}

private void SemanticCheck(WhileStatement ast, CompilerContext context)
{
Expand Down
16 changes: 16 additions & 0 deletions src/samples/while/interpreter/Interpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ public TypedValue Evaluate(Expression expr, InterpreterContext context)
if (expr is Neg neg) return Evaluate(neg, context);
if (expr is Not not) return Evaluate(not, context);
if (expr is Variable variable) return context.GetVariable(variable.Name);
if (expr is TernaryExpression ternary) return Evaluate(ternary, context);
throw new InterpreterException($"unknow expression type ({expr.GetType().Name})");
}

Expand Down Expand Up @@ -524,6 +525,21 @@ public TypedValue Evaluate(Not not, InterpreterContext context)
throw new InterpreterException($"invalid operation NOT {positiveVal.StringValue}");
return new TypedValue(!positiveVal.BoolValue);
}

public TypedValue Evaluate(TernaryExpression ternary, InterpreterContext context)
{
var condition = Evaluate(ternary.Condition, context);
if (condition.BoolValue)
{
var trueValue = Evaluate(ternary.TrueExpression, context);
return trueValue;
}
else
{
var falseValue = Evaluate(ternary.FalseExpression, context);
return falseValue;
}
}
}

#endregion
Expand Down
55 changes: 55 additions & 0 deletions src/samples/while/model/TernaryExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using csly.whileLang.compiler;
using Sigil;
using sly.lexer;

namespace csly.whileLang.model;

public class TernaryExpression : Expression
{
public LexerPosition Position { get; set; }
public Scope CompilerScope { get; set; }

public Expression Condition { get; set; }

public Expression TrueExpression { get; set; }

public Expression FalseExpression { get; set; }

public TernaryExpression(Expression condition, Expression trueExpression, Expression falseExpression)
{
Condition = condition;
TrueExpression = trueExpression;
FalseExpression = falseExpression;
}

public string Dump(string tab)
{
return $"{tab}{Condition.Dump("")} ? {TrueExpression.Dump("")} : {FalseExpression.Dump("")}";
}

public string Transpile(CompilerContext context)
{
return $"{Condition.Transpile(context)} ? {TrueExpression.Transpile(context)} : {FalseExpression.Transpile(context)};";
}

public Emit<Func<int>> EmitByteCode(CompilerContext context, Emit<Func<int>> emiter)
{
var thenLabel = emiter.DefineLabel();
var elseLabel = emiter.DefineLabel();
var endLabel = emiter.DefineLabel();
Condition.EmitByteCode(context, emiter);
emiter.BranchIfTrue(thenLabel);
emiter.Branch(elseLabel);
emiter.MarkLabel(thenLabel);
TrueExpression.EmitByteCode(context, emiter);
emiter.Branch(endLabel);
emiter.MarkLabel(elseLabel);
FalseExpression.EmitByteCode(context, emiter);
emiter.Branch(endLabel);
emiter.MarkLabel(endLabel);
return emiter;
}

public WhileType Whiletype { get; set; }
}
13 changes: 8 additions & 5 deletions tests/ParserTests/samples/IndentedWhileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ public void TestFString()
# fstring
v1 := 1
v2 := 2
fstring := $""v1 :> {v1} < v2 :> {v2} < v3 :> {v1+v2} < v4 :>{$""hello,"".$"" world""}<- end""
b := true
fstring := $""v1 :> {v1} < v2 :> {v2} < v3 :> {v1+v2} < v4 :>{$""hello,"".$"" world""}< v5 :>{(? b -> $""true"" | $""false"")}< - end""
";

Console.WriteLine("==================================");
Console.WriteLine("=== parse fstring");
Console.WriteLine("==================================");
Expand All @@ -231,19 +233,20 @@ public void TestFString()
Check.That(result.Result).IsNotNull();
Check.That(result.Result).IsInstanceOf<SequenceStatement>();
SequenceStatement seq = result.Result as SequenceStatement;
Check.That(seq.Count).IsEqualTo(3);
var fstringAssign = seq.Get(2) as AssignStatement;
Check.That(seq.Count).IsEqualTo(4);
var fstringAssign = seq.Get(3) as AssignStatement;
Check.That(fstringAssign).IsNotNull();
Check.That(fstringAssign.VariableName).IsEqualTo("fstring");
Check.That(fstringAssign.Value).IsInstanceOf<BinaryOperation>();
var fString = fstringAssign.Value as BinaryOperation;
Check.That(fString.Operator).IsEqualTo(BinaryOperator.CONCAT);
var interpreter = new Interpreter();
var context = interpreter.Interprete(result.Result, true);
Check.That(context.variables).CountIs(3);
Check.That(context.variables).CountIs(4);
Check.That(context).HasVariableWithIntValue("v1", 1);
Check.That(context).HasVariableWithIntValue("v2", 2);
Check.That(context).HasVariableWithStringValue("fstring", "v1 :> 1 < v2 :> 2 < v3 :> 3 < v4 :>hello, world<- end");
Check.That(context).HasVariableWithBoolValue("b", true);
Check.That(context).HasVariableWithStringValue("fstring", "v1 :> 1 < v2 :> 2 < v3 :> 3 < v4 :>hello, world< v5 :>true< - end");

}

Expand Down
11 changes: 11 additions & 0 deletions tests/ParserTests/samples/NFluentWhileExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ public static ICheckLink<ICheck<InterpreterContext>> HasVariableWithStringValue(
return ExtensibilityHelper.BuildCheckLink(context);
}

public static ICheckLink<ICheck<InterpreterContext>> HasVariableWithBoolValue(this ICheck<InterpreterContext> context, string variableName, bool expectedValue)
{
ExtensibilityHelper.BeginCheck(context)
.FailWhen(sut => sut.GetVariable(variableName) == null, "expecting {expected} but variable not found.")
.FailWhen(sut => sut.GetVariable(variableName).BoolValue != expectedValue, "expecting {expected} found {checked}.")
.OnNegate("variable is ok")
.DefineExpectedValue($"{variableName}={expectedValue}")
.EndCheck();
return ExtensibilityHelper.BuildCheckLink(context);
}

public static ICheckLink<ICheck<SequenceStatement>> CountIs(this ICheck<SequenceStatement> context, int expectedCount)
{
ExtensibilityHelper.BeginCheck(context)
Expand Down

0 comments on commit cbdcbf4

Please sign in to comment.