Skip to content

Commit cbdcbf4

Browse files
committed
add ternary expression to indented while
1 parent 9a79f41 commit cbdcbf4

File tree

7 files changed

+154
-10
lines changed

7 files changed

+154
-10
lines changed

src/samples/IndentedWhile/parser/IndentedWhileParserGeneric.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ public BinaryOperation BuildConcat(List<Expression> operands)
164164

165165
return null;
166166
}
167+
168+
[Production(
169+
"primary : QUESTION[d] IndentedWhileParserGeneric_expressions ARROW[d] IndentedWhileParserGeneric_expressions COLON[d] IndentedWhileParserGeneric_expressions")]
170+
public WhileAST TernaryQuestion(WhileAST condition, WhileAST ifTrue, WhileAST ifFalse)
171+
{
172+
return new TernaryExpression(condition as Expression, ifTrue as Expression, ifFalse as Expression);
173+
}
174+
175+
[Production("primary : OPEN_PAREN[d] IndentedWhileParserGeneric_expressions CLOSE_PAREN[d]")]
176+
public WhileAST Group(WhileAST expression) => expression;
167177

168178
// fstrings
169179
[Production("primary : OPEN_FSTRING[d] fstring_element* CLOSE_FSTRING[d]")]

src/samples/IndentedWhile/parser/IndentedWhileTokenGeneric.cs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,27 @@ public enum IndentedWhileTokenGeneric
9191

9292
[Mode(ModeAttribute.DefaultLexerMode, "fstringExpression")]
9393
[Lexeme(GenericToken.SugarToken, "/")] DIVIDE = 39,
94-
94+
95+
[Mode("default","fstringExpression")]
96+
[Sugar("?")]
97+
QUESTION,
98+
99+
[Mode("default","fstringExpression")]
100+
[Sugar("->")]
101+
ARROW,
102+
103+
[Mode("default","fstringExpression")]
104+
[Sugar("(")]
105+
OPEN_PAREN,
106+
107+
[Mode("default","fstringExpression")]
108+
[Sugar(")")]
109+
CLOSE_PAREN,
110+
111+
[Mode("default","fstringExpression")]
112+
[Sugar("|")]
113+
COLON,
114+
95115
#endregion
96116

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

107127
#region fstring 100 ->
108128

109-
[Push("fstringExpression")] [Mode("fstring")] [Sugar("{")]
129+
[Push("fstringExpression")]
130+
[Mode("fstring")]
131+
[Sugar("{")]
110132
OPEN_FSTRING_EXPPRESSION = 100,
111133

112-
[Pop] [Mode("fstringExpression")] [Sugar("}")]
134+
[Pop]
135+
[Mode("fstringExpression")]
136+
[Sugar("}")]
113137
CLOSE_FSTRING_EXPPRESSION = 101,
114138

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

125149

126-
[Mode("fstring", "fstringExpression")]
150+
[Mode("fstring")]
127151
[UpTo("{","\"")]
128-
FSTRING_CONTENT
152+
FSTRING_CONTENT,
153+
154+
155+
156+
157+
129158

130159

131160
#endregion

src/samples/while/compiler/SemanticChecker.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,26 @@ private void SemanticCheck(IfStatement ast, CompilerContext context)
8787
SemanticCheck(ast.ElseStmt,context);
8888
context.CloseScope();
8989
}
90+
91+
private void SemanticCheck(TernaryExpression ast, CompilerContext context)
92+
{
93+
var val = expressionTyper.TypeExpression(ast.Condition, context);
94+
if (val != WhileType.BOOL)
95+
throw new SignatureException($"invalid condition type {ast.Condition.Dump("")} at {ast.Position}");
96+
ast.CompilerScope = context.CurrentScope;
97+
98+
context.OpenNewScope();
99+
var trueType = expressionTyper.TypeExpression(ast.TrueExpression, context);
100+
context.CloseScope();
101+
102+
context.OpenNewScope();
103+
var falseType = expressionTyper.TypeExpression(ast.TrueExpression, context);
104+
context.CloseScope();
105+
if (trueType != falseType)
106+
{
107+
throw new TypingException($"ternary expression at {ast.Position} has different branch types . {trueType} vis different from {falseType}");
108+
}
109+
}
90110

91111
private void SemanticCheck(WhileStatement ast, CompilerContext context)
92112
{

src/samples/while/interpreter/Interpreter.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ public TypedValue Evaluate(Expression expr, InterpreterContext context)
324324
if (expr is Neg neg) return Evaluate(neg, context);
325325
if (expr is Not not) return Evaluate(not, context);
326326
if (expr is Variable variable) return context.GetVariable(variable.Name);
327+
if (expr is TernaryExpression ternary) return Evaluate(ternary, context);
327328
throw new InterpreterException($"unknow expression type ({expr.GetType().Name})");
328329
}
329330

@@ -524,6 +525,21 @@ public TypedValue Evaluate(Not not, InterpreterContext context)
524525
throw new InterpreterException($"invalid operation NOT {positiveVal.StringValue}");
525526
return new TypedValue(!positiveVal.BoolValue);
526527
}
528+
529+
public TypedValue Evaluate(TernaryExpression ternary, InterpreterContext context)
530+
{
531+
var condition = Evaluate(ternary.Condition, context);
532+
if (condition.BoolValue)
533+
{
534+
var trueValue = Evaluate(ternary.TrueExpression, context);
535+
return trueValue;
536+
}
537+
else
538+
{
539+
var falseValue = Evaluate(ternary.FalseExpression, context);
540+
return falseValue;
541+
}
542+
}
527543
}
528544

529545
#endregion
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using csly.whileLang.compiler;
3+
using Sigil;
4+
using sly.lexer;
5+
6+
namespace csly.whileLang.model;
7+
8+
public class TernaryExpression : Expression
9+
{
10+
public LexerPosition Position { get; set; }
11+
public Scope CompilerScope { get; set; }
12+
13+
public Expression Condition { get; set; }
14+
15+
public Expression TrueExpression { get; set; }
16+
17+
public Expression FalseExpression { get; set; }
18+
19+
public TernaryExpression(Expression condition, Expression trueExpression, Expression falseExpression)
20+
{
21+
Condition = condition;
22+
TrueExpression = trueExpression;
23+
FalseExpression = falseExpression;
24+
}
25+
26+
public string Dump(string tab)
27+
{
28+
return $"{tab}{Condition.Dump("")} ? {TrueExpression.Dump("")} : {FalseExpression.Dump("")}";
29+
}
30+
31+
public string Transpile(CompilerContext context)
32+
{
33+
return $"{Condition.Transpile(context)} ? {TrueExpression.Transpile(context)} : {FalseExpression.Transpile(context)};";
34+
}
35+
36+
public Emit<Func<int>> EmitByteCode(CompilerContext context, Emit<Func<int>> emiter)
37+
{
38+
var thenLabel = emiter.DefineLabel();
39+
var elseLabel = emiter.DefineLabel();
40+
var endLabel = emiter.DefineLabel();
41+
Condition.EmitByteCode(context, emiter);
42+
emiter.BranchIfTrue(thenLabel);
43+
emiter.Branch(elseLabel);
44+
emiter.MarkLabel(thenLabel);
45+
TrueExpression.EmitByteCode(context, emiter);
46+
emiter.Branch(endLabel);
47+
emiter.MarkLabel(elseLabel);
48+
FalseExpression.EmitByteCode(context, emiter);
49+
emiter.Branch(endLabel);
50+
emiter.MarkLabel(endLabel);
51+
return emiter;
52+
}
53+
54+
public WhileType Whiletype { get; set; }
55+
}

tests/ParserTests/samples/IndentedWhileTests.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,10 @@ public void TestFString()
220220
# fstring
221221
v1 := 1
222222
v2 := 2
223-
fstring := $""v1 :> {v1} < v2 :> {v2} < v3 :> {v1+v2} < v4 :>{$""hello,"".$"" world""}<- end""
223+
b := true
224+
fstring := $""v1 :> {v1} < v2 :> {v2} < v3 :> {v1+v2} < v4 :>{$""hello,"".$"" world""}< v5 :>{(? b -> $""true"" | $""false"")}< - end""
224225
";
226+
225227
Console.WriteLine("==================================");
226228
Console.WriteLine("=== parse fstring");
227229
Console.WriteLine("==================================");
@@ -231,19 +233,20 @@ public void TestFString()
231233
Check.That(result.Result).IsNotNull();
232234
Check.That(result.Result).IsInstanceOf<SequenceStatement>();
233235
SequenceStatement seq = result.Result as SequenceStatement;
234-
Check.That(seq.Count).IsEqualTo(3);
235-
var fstringAssign = seq.Get(2) as AssignStatement;
236+
Check.That(seq.Count).IsEqualTo(4);
237+
var fstringAssign = seq.Get(3) as AssignStatement;
236238
Check.That(fstringAssign).IsNotNull();
237239
Check.That(fstringAssign.VariableName).IsEqualTo("fstring");
238240
Check.That(fstringAssign.Value).IsInstanceOf<BinaryOperation>();
239241
var fString = fstringAssign.Value as BinaryOperation;
240242
Check.That(fString.Operator).IsEqualTo(BinaryOperator.CONCAT);
241243
var interpreter = new Interpreter();
242244
var context = interpreter.Interprete(result.Result, true);
243-
Check.That(context.variables).CountIs(3);
245+
Check.That(context.variables).CountIs(4);
244246
Check.That(context).HasVariableWithIntValue("v1", 1);
245247
Check.That(context).HasVariableWithIntValue("v2", 2);
246-
Check.That(context).HasVariableWithStringValue("fstring", "v1 :> 1 < v2 :> 2 < v3 :> 3 < v4 :>hello, world<- end");
248+
Check.That(context).HasVariableWithBoolValue("b", true);
249+
Check.That(context).HasVariableWithStringValue("fstring", "v1 :> 1 < v2 :> 2 < v3 :> 3 < v4 :>hello, world< v5 :>true< - end");
247250

248251
}
249252

tests/ParserTests/samples/NFluentWhileExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ public static ICheckLink<ICheck<InterpreterContext>> HasVariableWithStringValue(
2929
return ExtensibilityHelper.BuildCheckLink(context);
3030
}
3131

32+
public static ICheckLink<ICheck<InterpreterContext>> HasVariableWithBoolValue(this ICheck<InterpreterContext> context, string variableName, bool expectedValue)
33+
{
34+
ExtensibilityHelper.BeginCheck(context)
35+
.FailWhen(sut => sut.GetVariable(variableName) == null, "expecting {expected} but variable not found.")
36+
.FailWhen(sut => sut.GetVariable(variableName).BoolValue != expectedValue, "expecting {expected} found {checked}.")
37+
.OnNegate("variable is ok")
38+
.DefineExpectedValue($"{variableName}={expectedValue}")
39+
.EndCheck();
40+
return ExtensibilityHelper.BuildCheckLink(context);
41+
}
42+
3243
public static ICheckLink<ICheck<SequenceStatement>> CountIs(this ICheck<SequenceStatement> context, int expectedCount)
3344
{
3445
ExtensibilityHelper.BeginCheck(context)

0 commit comments

Comments
 (0)