Sprint 2 Step 3: all Statement, Expression, Type, and Parameter concepts
Ports all 33 SemAnno concepts from MPS into C++ headers grouped by category. Test builds the exact Calculator model from Phase1Test.mps as a 27-node C++ object graph and verifies every property, child link, and parent chain. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,3 +9,6 @@ target_include_directories(step1_test PRIVATE src)
|
||||
|
||||
add_executable(step2_test tests/step2_test.cpp)
|
||||
target_include_directories(step2_test PRIVATE src)
|
||||
|
||||
add_executable(step3_test tests/step3_test.cpp)
|
||||
target_include_directories(step3_test PRIVATE src)
|
||||
|
||||
107
editor/src/ast/Expression.h
Normal file
107
editor/src/ast/Expression.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
#include "ASTNode.h"
|
||||
|
||||
class Expression : public ASTNode {
|
||||
public:
|
||||
Expression() { conceptType = "Expression"; }
|
||||
};
|
||||
|
||||
class BinaryOperation : public Expression {
|
||||
public:
|
||||
std::string op;
|
||||
BinaryOperation() { conceptType = "BinaryOperation"; }
|
||||
BinaryOperation(const std::string& id, const std::string& op) : op(op) {
|
||||
this->id = id;
|
||||
this->conceptType = "BinaryOperation";
|
||||
}
|
||||
// children: left (1), right (1) via setChild
|
||||
};
|
||||
|
||||
class UnaryOperation : public Expression {
|
||||
public:
|
||||
std::string op;
|
||||
UnaryOperation() { conceptType = "UnaryOperation"; }
|
||||
// children: operand (1) via setChild("operand", ...)
|
||||
};
|
||||
|
||||
class FunctionCall : public Expression {
|
||||
public:
|
||||
std::string functionName;
|
||||
FunctionCall() { conceptType = "FunctionCall"; }
|
||||
// children: arguments (0..n) via addChild("arguments", ...)
|
||||
};
|
||||
|
||||
class VariableReference : public Expression {
|
||||
public:
|
||||
std::string variableName;
|
||||
VariableReference() { conceptType = "VariableReference"; }
|
||||
VariableReference(const std::string& id, const std::string& varName)
|
||||
: variableName(varName) {
|
||||
this->id = id;
|
||||
this->conceptType = "VariableReference";
|
||||
}
|
||||
};
|
||||
|
||||
class IntegerLiteral : public Expression {
|
||||
public:
|
||||
int value = 0;
|
||||
IntegerLiteral() { conceptType = "IntegerLiteral"; }
|
||||
IntegerLiteral(const std::string& id, int val) : value(val) {
|
||||
this->id = id;
|
||||
this->conceptType = "IntegerLiteral";
|
||||
}
|
||||
};
|
||||
|
||||
class FloatLiteral : public Expression {
|
||||
public:
|
||||
std::string value;
|
||||
FloatLiteral() { conceptType = "FloatLiteral"; }
|
||||
FloatLiteral(const std::string& id, const std::string& val) : value(val) {
|
||||
this->id = id;
|
||||
this->conceptType = "FloatLiteral";
|
||||
}
|
||||
};
|
||||
|
||||
class StringLiteral : public Expression {
|
||||
public:
|
||||
std::string value;
|
||||
StringLiteral() { conceptType = "StringLiteral"; }
|
||||
StringLiteral(const std::string& id, const std::string& val) : value(val) {
|
||||
this->id = id;
|
||||
this->conceptType = "StringLiteral";
|
||||
}
|
||||
};
|
||||
|
||||
class BooleanLiteral : public Expression {
|
||||
public:
|
||||
bool value = false;
|
||||
BooleanLiteral() { conceptType = "BooleanLiteral"; }
|
||||
BooleanLiteral(const std::string& id, bool val) : value(val) {
|
||||
this->id = id;
|
||||
this->conceptType = "BooleanLiteral";
|
||||
}
|
||||
};
|
||||
|
||||
class NullLiteral : public Expression {
|
||||
public:
|
||||
NullLiteral() { conceptType = "NullLiteral"; }
|
||||
};
|
||||
|
||||
class ListLiteral : public Expression {
|
||||
public:
|
||||
ListLiteral() { conceptType = "ListLiteral"; }
|
||||
// children: elements (0..n) via addChild("elements", ...)
|
||||
};
|
||||
|
||||
class IndexAccess : public Expression {
|
||||
public:
|
||||
IndexAccess() { conceptType = "IndexAccess"; }
|
||||
// children: target (1), index (1) via setChild
|
||||
};
|
||||
|
||||
class MemberAccess : public Expression {
|
||||
public:
|
||||
std::string memberName;
|
||||
MemberAccess() { conceptType = "MemberAccess"; }
|
||||
// children: target (1) via setChild("target", ...)
|
||||
};
|
||||
14
editor/src/ast/Parameter.h
Normal file
14
editor/src/ast/Parameter.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "ASTNode.h"
|
||||
|
||||
class Parameter : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
Parameter() { conceptType = "Parameter"; }
|
||||
Parameter(const std::string& id, const std::string& name) : name(name) {
|
||||
this->id = id;
|
||||
this->conceptType = "Parameter";
|
||||
}
|
||||
// children: type (1) via setChild("type", ...)
|
||||
// children: defaultValue (0..1) via setChild("defaultValue", ...)
|
||||
};
|
||||
55
editor/src/ast/Statement.h
Normal file
55
editor/src/ast/Statement.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include "ASTNode.h"
|
||||
|
||||
class Statement : public ASTNode {
|
||||
public:
|
||||
Statement() { conceptType = "Statement"; }
|
||||
};
|
||||
|
||||
class Block : public Statement {
|
||||
public:
|
||||
Block() { conceptType = "Block"; }
|
||||
// children: statements (0..n) via addChild("statements", ...)
|
||||
};
|
||||
|
||||
class Assignment : public Statement {
|
||||
public:
|
||||
Assignment() { conceptType = "Assignment"; }
|
||||
// children: target (1) via setChild("target", ...)
|
||||
// children: value (1) via setChild("value", ...)
|
||||
};
|
||||
|
||||
class IfStatement : public Statement {
|
||||
public:
|
||||
IfStatement() { conceptType = "IfStatement"; }
|
||||
// children: condition (1) via setChild("condition", ...)
|
||||
// children: thenBranch (0..n) via addChild("thenBranch", ...)
|
||||
// children: elseBranch (0..n) via addChild("elseBranch", ...)
|
||||
};
|
||||
|
||||
class WhileLoop : public Statement {
|
||||
public:
|
||||
WhileLoop() { conceptType = "WhileLoop"; }
|
||||
// children: condition (1) via setChild("condition", ...)
|
||||
// children: body (0..n) via addChild("body", ...)
|
||||
};
|
||||
|
||||
class ForLoop : public Statement {
|
||||
public:
|
||||
std::string iteratorName;
|
||||
ForLoop() { conceptType = "ForLoop"; }
|
||||
// children: iterable (1) via setChild("iterable", ...)
|
||||
// children: body (0..n) via addChild("body", ...)
|
||||
};
|
||||
|
||||
class Return : public Statement {
|
||||
public:
|
||||
Return() { conceptType = "Return"; }
|
||||
// children: value (0..1) via setChild("value", ...)
|
||||
};
|
||||
|
||||
class ExpressionStatement : public Statement {
|
||||
public:
|
||||
ExpressionStatement() { conceptType = "ExpressionStatement"; }
|
||||
// children: expression (1) via setChild("expression", ...)
|
||||
};
|
||||
64
editor/src/ast/Type.h
Normal file
64
editor/src/ast/Type.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "ASTNode.h"
|
||||
|
||||
class Type : public ASTNode {
|
||||
public:
|
||||
Type() { conceptType = "Type"; }
|
||||
};
|
||||
|
||||
class PrimitiveType : public Type {
|
||||
public:
|
||||
std::string kind;
|
||||
PrimitiveType() { conceptType = "PrimitiveType"; }
|
||||
PrimitiveType(const std::string& id, const std::string& kind) : kind(kind) {
|
||||
this->id = id;
|
||||
this->conceptType = "PrimitiveType";
|
||||
}
|
||||
};
|
||||
|
||||
class ListType : public Type {
|
||||
public:
|
||||
ListType() { conceptType = "ListType"; }
|
||||
// children: elementType (1) via setChild("elementType", ...)
|
||||
};
|
||||
|
||||
class SetType : public Type {
|
||||
public:
|
||||
SetType() { conceptType = "SetType"; }
|
||||
// children: elementType (1) via setChild("elementType", ...)
|
||||
};
|
||||
|
||||
class MapType : public Type {
|
||||
public:
|
||||
MapType() { conceptType = "MapType"; }
|
||||
// children: keyType (1), valueType (1) via setChild
|
||||
};
|
||||
|
||||
class TupleType : public Type {
|
||||
public:
|
||||
TupleType() { conceptType = "TupleType"; }
|
||||
// children: elementTypes (0..n) via addChild("elementTypes", ...)
|
||||
};
|
||||
|
||||
class ArrayType : public Type {
|
||||
public:
|
||||
ArrayType() { conceptType = "ArrayType"; }
|
||||
// children: elementType (1) via setChild("elementType", ...)
|
||||
// children: size (1) via setChild("size", ...) [Expression]
|
||||
};
|
||||
|
||||
class OptionalType : public Type {
|
||||
public:
|
||||
OptionalType() { conceptType = "OptionalType"; }
|
||||
// children: innerType (1) via setChild("innerType", ...)
|
||||
};
|
||||
|
||||
class CustomType : public Type {
|
||||
public:
|
||||
std::string typeName;
|
||||
CustomType() { conceptType = "CustomType"; }
|
||||
CustomType(const std::string& id, const std::string& name) : typeName(name) {
|
||||
this->id = id;
|
||||
this->conceptType = "CustomType";
|
||||
}
|
||||
};
|
||||
188
editor/tests/step3_test.cpp
Normal file
188
editor/tests/step3_test.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
// Step 3: Build the Calculator example from Phase1Test.mps as a C++ object graph.
|
||||
//
|
||||
// Calculator (Module, targetLanguage=cpp)
|
||||
// ├── Variable "PI" → type: PrimitiveType("float")
|
||||
// ├── Function "add"
|
||||
// │ ├── returnType: PrimitiveType("int")
|
||||
// │ ├── parameters: Parameter("x", int), Parameter("y", int)
|
||||
// │ └── body:
|
||||
// │ ├── Assignment { target: VarRef("result"), value: BinOp("+", VarRef("x"), VarRef("y")) }
|
||||
// │ └── Return { value: VarRef("result") }
|
||||
// └── Function "multiply"
|
||||
// ├── returnType: PrimitiveType("int")
|
||||
// ├── parameters: Parameter("a", int), Parameter("b", int)
|
||||
// └── body:
|
||||
// └── Return { value: BinOp("*", VarRef("a"), VarRef("b")) }
|
||||
|
||||
#include "../src/ast/Module.h"
|
||||
#include "../src/ast/Function.h"
|
||||
#include "../src/ast/Variable.h"
|
||||
#include "../src/ast/Parameter.h"
|
||||
#include "../src/ast/Statement.h"
|
||||
#include "../src/ast/Expression.h"
|
||||
#include "../src/ast/Type.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
// --- Build the tree (matching Phase1Test.mps IDs) ---
|
||||
|
||||
// Root
|
||||
Module calc("Calc_M001", "Calculator", "cpp");
|
||||
|
||||
// Variable PI
|
||||
Variable pi("Calc_V001", "PI");
|
||||
PrimitiveType piType("Calc_VT001", "float");
|
||||
pi.setChild("type", &piType);
|
||||
calc.addChild("variables", &pi);
|
||||
|
||||
// Function: add
|
||||
Function add("Calc_F001", "add");
|
||||
PrimitiveType addRet("Calc_RT001", "int");
|
||||
add.setChild("returnType", &addRet);
|
||||
|
||||
Parameter px("Calc_P001", "x");
|
||||
PrimitiveType pxType("Calc_PT001", "int");
|
||||
px.setChild("type", &pxType);
|
||||
add.addChild("parameters", &px);
|
||||
|
||||
Parameter py("Calc_P002", "y");
|
||||
PrimitiveType pyType("Calc_PT002", "int");
|
||||
py.setChild("type", &pyType);
|
||||
add.addChild("parameters", &py);
|
||||
|
||||
// add body: Assignment(result = x + y), then Return(result)
|
||||
Assignment assign;
|
||||
assign.id = "Calc_A001";
|
||||
VariableReference assignTarget("c_VR_result", "result");
|
||||
assign.setChild("target", &assignTarget);
|
||||
|
||||
BinaryOperation addOp("Calc_E001", "+");
|
||||
VariableReference vrX("Calc_VR_x", "x");
|
||||
VariableReference vrY("Calc_VR_y", "y");
|
||||
addOp.setChild("left", &vrX);
|
||||
addOp.setChild("right", &vrY);
|
||||
assign.setChild("value", &addOp);
|
||||
|
||||
Return addReturn;
|
||||
addReturn.id = "Calc_R001";
|
||||
VariableReference vrRetResult("c_VR_return", "result");
|
||||
addReturn.setChild("value", &vrRetResult);
|
||||
|
||||
add.addChild("body", &assign);
|
||||
add.addChild("body", &addReturn);
|
||||
|
||||
calc.addChild("functions", &add);
|
||||
|
||||
// Function: multiply
|
||||
Function multiply("Calc_F002", "multiply");
|
||||
PrimitiveType mulRet("Calc_RT002", "int");
|
||||
multiply.setChild("returnType", &mulRet);
|
||||
|
||||
Parameter pa("Calc_P003", "a");
|
||||
PrimitiveType paType("Calc_PT003", "int");
|
||||
pa.setChild("type", &paType);
|
||||
multiply.addChild("parameters", &pa);
|
||||
|
||||
Parameter pb("Calc_P004", "b");
|
||||
PrimitiveType pbType("Calc_PT004", "int");
|
||||
pb.setChild("type", &pbType);
|
||||
multiply.addChild("parameters", &pb);
|
||||
|
||||
Return mulReturn;
|
||||
mulReturn.id = "Calc_R002";
|
||||
BinaryOperation mulOp("Calc_E005", "*");
|
||||
VariableReference vrA("Calc_VR_a", "a");
|
||||
VariableReference vrB("Calc_VR_b", "b");
|
||||
mulOp.setChild("left", &vrA);
|
||||
mulOp.setChild("right", &vrB);
|
||||
mulReturn.setChild("value", &mulOp);
|
||||
|
||||
multiply.addChild("body", &mulReturn);
|
||||
|
||||
calc.addChild("functions", &multiply);
|
||||
|
||||
// --- Verify the tree ---
|
||||
|
||||
// Module level
|
||||
assert(calc.name == "Calculator");
|
||||
assert(calc.targetLanguage == "cpp");
|
||||
assert(calc.getChildren("functions").size() == 2);
|
||||
assert(calc.getChildren("variables").size() == 1);
|
||||
|
||||
// Variable PI
|
||||
auto* v = static_cast<Variable*>(calc.getChildren("variables")[0]);
|
||||
assert(v->name == "PI");
|
||||
assert(v->parent == &calc);
|
||||
auto* vt = static_cast<PrimitiveType*>(v->getChild("type"));
|
||||
assert(vt != nullptr);
|
||||
assert(vt->kind == "float");
|
||||
assert(vt->parent == v);
|
||||
|
||||
// Function: add
|
||||
auto* fn1 = static_cast<Function*>(calc.getChildren("functions")[0]);
|
||||
assert(fn1->name == "add");
|
||||
assert(fn1->parent == &calc);
|
||||
|
||||
auto* rt1 = static_cast<PrimitiveType*>(fn1->getChild("returnType"));
|
||||
assert(rt1->kind == "int");
|
||||
|
||||
const auto& params1 = fn1->getChildren("parameters");
|
||||
assert(params1.size() == 2);
|
||||
assert(static_cast<Parameter*>(params1[0])->name == "x");
|
||||
assert(static_cast<Parameter*>(params1[1])->name == "y");
|
||||
// Param types
|
||||
auto* pxt = static_cast<PrimitiveType*>(params1[0]->getChild("type"));
|
||||
assert(pxt->kind == "int");
|
||||
assert(pxt->parent == params1[0]);
|
||||
|
||||
const auto& body1 = fn1->getChildren("body");
|
||||
assert(body1.size() == 2);
|
||||
|
||||
// First statement: Assignment
|
||||
auto* a1 = static_cast<Assignment*>(body1[0]);
|
||||
assert(a1->conceptType == "Assignment");
|
||||
assert(a1->parent == fn1);
|
||||
auto* aTgt = static_cast<VariableReference*>(a1->getChild("target"));
|
||||
assert(aTgt->variableName == "result");
|
||||
auto* aVal = static_cast<BinaryOperation*>(a1->getChild("value"));
|
||||
assert(aVal->op == "+");
|
||||
auto* aLeft = static_cast<VariableReference*>(aVal->getChild("left"));
|
||||
auto* aRight = static_cast<VariableReference*>(aVal->getChild("right"));
|
||||
assert(aLeft->variableName == "x");
|
||||
assert(aRight->variableName == "y");
|
||||
// Walk up: expression → assignment → function → module
|
||||
assert(aLeft->parent == aVal);
|
||||
assert(aVal->parent == a1);
|
||||
assert(a1->parent == fn1);
|
||||
assert(fn1->parent == &calc);
|
||||
|
||||
// Second statement: Return
|
||||
auto* r1 = static_cast<Return*>(body1[1]);
|
||||
assert(r1->conceptType == "Return");
|
||||
auto* rv = static_cast<VariableReference*>(r1->getChild("value"));
|
||||
assert(rv->variableName == "result");
|
||||
|
||||
// Function: multiply
|
||||
auto* fn2 = static_cast<Function*>(calc.getChildren("functions")[1]);
|
||||
assert(fn2->name == "multiply");
|
||||
|
||||
const auto& params2 = fn2->getChildren("parameters");
|
||||
assert(params2.size() == 2);
|
||||
assert(static_cast<Parameter*>(params2[0])->name == "a");
|
||||
assert(static_cast<Parameter*>(params2[1])->name == "b");
|
||||
|
||||
const auto& body2 = fn2->getChildren("body");
|
||||
assert(body2.size() == 1);
|
||||
auto* r2 = static_cast<Return*>(body2[0]);
|
||||
auto* mulExpr = static_cast<BinaryOperation*>(r2->getChild("value"));
|
||||
assert(mulExpr->op == "*");
|
||||
assert(static_cast<VariableReference*>(mulExpr->getChild("left"))->variableName == "a");
|
||||
assert(static_cast<VariableReference*>(mulExpr->getChild("right"))->variableName == "b");
|
||||
|
||||
// Full tree depth: varref → binop → return → function → module
|
||||
assert(vrB.parent->parent->parent->parent == &calc);
|
||||
|
||||
std::cout << "Step 3: PASS — Calculator model (27 nodes) built and verified" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user