diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java index 6513427..138dcfe 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java @@ -11,34 +11,9 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType; import org.jcnc.snow.compiler.semantic.type.Type; /** - * 二元表达式分析器:负责对形如 left op right 的表达式进行类型推导和类型检查。 - *

- * 支持以下运算符: - *

- * 对于未知运算符或类型不匹配的情况,会在 {@link Context#getErrors() 错误列表} 中加入对应的 - * {@link SemanticError},并将结果类型降级为 {@link BuiltinType#INT} 以避免后续连锁错误。 + * 二元表达式分析器:支持数值宽化转换及字符串拼接。 */ public class BinaryExpressionAnalyzer implements ExpressionAnalyzer { - - /** - * 对给定的二元表达式节点进行语义分析,返回推导出的类型。 - * - * @param ctx 全局上下文,包含模块表、错误收集、日志开关、注册表等 - * @param mi 当前正在分析的模块信息,用于查找导入、函数签名等 - * @param fn 当前正在分析的函数节点,用于处理返回类型检查等(可用于更复杂场景) - * @param locals 当前作用域的符号表,包含已定义的局部变量及其类型 - * @param bin 待分析的 {@link BinaryExpressionNode} 节点,包含左子表达式、运算符、右子表达式 - * @return 推导出的 {@link Type}: - * - */ @Override public Type analyze(Context ctx, ModuleInfo mi, @@ -47,64 +22,40 @@ public class BinaryExpressionAnalyzer implements ExpressionAnalyzer { - // 字符串拼接 或 整数相加 - if (left == BuiltinType.STRING || right == BuiltinType.STRING) { - result = BuiltinType.STRING; - } else if (left == BuiltinType.INT && right == BuiltinType.INT) { - result = BuiltinType.INT; - } else { - result = null; + // 字符串拼接 + if (op.equals("+") && + (left == BuiltinType.STRING || right == BuiltinType.STRING)) { + return BuiltinType.STRING; + } + + // 数值运算或比较 + if ("+-*/%".contains(op) || + ("<<=>>===!=").contains(op)) { + if (left.isNumeric() && right.isNumeric()) { + // 自动宽化到更宽的数值类型 + Type wide = Type.widen(left, right); + if (wide == null) wide = BuiltinType.INT; // 容错降级 + // 比较运算返回 int + if ("< <= > >= == !=".contains(op)) { + return BuiltinType.INT; } - } - case "-", "*", "/", "%" -> { - // 数学运算,要求整数操作数 - if (left == BuiltinType.INT && right == BuiltinType.INT) { - result = BuiltinType.INT; - } else { - result = null; - } - } - case "<", "<=", ">", ">=", "==", "!=" -> { - // 比较运算,要求整数操作数,返回整数表示真假 - if (left == BuiltinType.INT && right == BuiltinType.INT) { - result = BuiltinType.INT; - } else { - result = null; - } - } - default -> { - // 未知运算符 - ctx.getErrors().add(new SemanticError(bin, "未知运算符: " + op)); - ctx.log("错误: 未知运算符 " + op); - return BuiltinType.INT; + return wide; } } - // 如果推导失败(类型不匹配),记录错误并降级 - if (result == null) { - ctx.getErrors().add(new SemanticError( - bin, - String.format("运算符 '%s' 不支持类型: %s 和 %s", op, left, right)) - ); - ctx.log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right); - result = BuiltinType.INT; - } else { - ctx.log("二元表达式推导类型: " + result); - } - - return result; + // 未知或不支持的运算符/类型 + ctx.getErrors().add(new SemanticError( + bin, + String.format("运算符 '%s' 不支持类型: %s 和 %s", op, left, right) + )); + ctx.log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right); + return BuiltinType.INT; } } diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java index cf4c6bd..603eb12 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java @@ -1,9 +1,6 @@ package org.jcnc.snow.compiler.semantic.analyzers.expression; -import org.jcnc.snow.compiler.parser.ast.CallExpressionNode; -import org.jcnc.snow.compiler.parser.ast.FunctionNode; -import org.jcnc.snow.compiler.parser.ast.IdentifierNode; -import org.jcnc.snow.compiler.parser.ast.MemberExpressionNode; +import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer; import org.jcnc.snow.compiler.semantic.core.Context; @@ -19,38 +16,13 @@ import java.util.List; /** * 函数调用表达式分析器:负责对 callee(arg1, arg2, ...) 形式的调用进行 - * 语义检查和类型推导。 - *

- * 支持两种调用方式: + * 语义检查和类型推导,并支持: *

- *

- * 分析内容包括: - *

    - *
  1. 解析目标模块与函数名;
  2. - *
  3. 检查函数是否已定义;
  4. - *
  5. 递归分析并收集所有实参的类型;
  6. - *
  7. 检查参数个数与参数类型是否与函数签名匹配;
  8. - *
  9. 返回函数签名中的返回类型;
  10. - *
  11. 在任何错误(未知模块、未导入模块、调用方式不支持、函数未定义、 - * 参数数量或类型不匹配)时,记录对应的 {@link SemanticError}, - * 并降级返回 {@link BuiltinType#INT} 以避免后续连锁错误。
  12. - *
*/ public class CallExpressionAnalyzer implements ExpressionAnalyzer { - - /** - * 对给定的调用表达式节点进行语义分析,返回推导出的类型。 - * - * @param ctx 全局上下文,包含模块表、错误收集、日志输出、分析器注册表等 - * @param mi 当前正在分析的模块信息,用于查找导入列表和函数签名 - * @param fn 当前正在分析的函数节点,可用于更复杂的上下文校验 - * @param locals 当前作用域的符号表,包含已定义的变量及其类型 - * @param call 待分析的 {@link CallExpressionNode},包含被调用的表达式和实参列表 - * @return 推导出的函数返回类型;若发生任何错误,则降级返回 {@link BuiltinType#INT} - */ @Override public Type analyze(Context ctx, ModuleInfo mi, @@ -58,35 +30,26 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer args = new ArrayList<>(); - for (var argExpr : call.arguments()) { - var argAnalyzer = ctx.getRegistry().getExpressionAnalyzer(argExpr); - args.add(argAnalyzer.analyze(ctx, mi, fn, locals, argExpr)); + for (ExpressionNode arg : call.arguments()) { + args.add(ctx.getRegistry().getExpressionAnalyzer(arg) + .analyze(ctx, mi, fn, locals, arg)); } - // 参数数量检查 + // 参数检查(数量 + 类型兼容 / 宽化 / 数值->字符串隐式转换) if (args.size() != ft.paramTypes().size()) { ctx.getErrors().add(new SemanticError(call, - "参数数量不匹配: 期望 " - + ft.paramTypes().size() - + " 个, 实际 " - + args.size() - + " 个")); + "参数数量不匹配: 期望 " + ft.paramTypes().size() + + " 个, 实际 " + args.size() + " 个")); ctx.log("错误: 参数数量不匹配: 期望 " - + ft.paramTypes().size() - + ", 实际 " - + args.size()); + + ft.paramTypes().size() + ", 实际 " + args.size()); + } else { - // 参数类型检查 for (int i = 0; i < args.size(); i++) { Type expected = ft.paramTypes().get(i); - Type actual = args.get(i); - if (!expected.isCompatible(actual)) { + Type actual = args.get(i); + + // 完全兼容或宽化兼容 + boolean ok = expected.isCompatible(actual) + || (expected.isNumeric() && actual.isNumeric() + && Type.widen(actual, expected) == expected); + + // 数值到字符串的隐式转换 + if (!ok + && expected == BuiltinType.STRING + && actual.isNumeric()) { + ctx.log(String.format( + "隐式将参数 %d 的数值类型 %s 转换为 string (to_string)", + i, actual + )); + ok = true; + } + + if (!ok) { ctx.getErrors().add(new SemanticError(call, String.format("参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", i, expected, actual))); - ctx.log("错误: 参数类型不匹配 (位置 " - + i - + "): 期望 " - + expected - + ", 实际 " - + actual); + ctx.log("错误: 参数类型不匹配 (位置 " + i + "): 期望 " + + expected + ", 实际 " + actual); } } } diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java index 93c6c44..8902ce6 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java @@ -6,34 +6,13 @@ import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer; import org.jcnc.snow.compiler.semantic.core.Context; import org.jcnc.snow.compiler.semantic.core.ModuleInfo; import org.jcnc.snow.compiler.semantic.error.SemanticError; -import org.jcnc.snow.compiler.semantic.symbol.Symbol; -import org.jcnc.snow.compiler.semantic.symbol.SymbolKind; -import org.jcnc.snow.compiler.semantic.symbol.SymbolTable; +import org.jcnc.snow.compiler.semantic.symbol.*; import org.jcnc.snow.compiler.semantic.type.Type; /** - * 赋值语句分析器:负责对 {@link AssignmentNode} 节点进行语义检查。 - *

- * 分析步骤: - *

    - *
  1. 检查目标变量是否已在当前作用域中声明且种类为 {@link SymbolKind#VARIABLE};
  2. - *
  3. 递归分析赋值右侧表达式,获取其类型;
  4. - *
  5. 检查右侧表达式类型是否与目标变量类型兼容;
  6. - *
  7. 在任一检查失败时,向 {@link Context#getErrors() 错误列表} 中添加对应的 - * {@link SemanticError} 并记录日志。
  8. - *
+ * 赋值语句分析器:支持数值宽化自动转换。 */ public class AssignmentAnalyzer implements StatementAnalyzer { - - /** - * 对给定的赋值语句节点进行语义分析。 - * - * @param ctx 全局上下文,包含模块表、错误收集、日志输出和分析器注册表等 - * @param mi 当前模块信息,用于处理跨模块符号(此分析器不使用模块上下文) - * @param fn 当前函数节点,可用于更复杂的上下文校验(此分析器不使用函数上下文) - * @param locals 当前作用域的符号表,包含已声明的符号及其类型 - * @param asg 待分析的 {@link AssignmentNode},包含目标变量名和赋值表达式 - */ @Override public void analyze(Context ctx, ModuleInfo mi, @@ -41,29 +20,26 @@ public class AssignmentAnalyzer implements StatementAnalyzer { SymbolTable locals, AssignmentNode asg) { ctx.log("赋值检查: " + asg.variable()); - - // 1. 检查变量声明 Symbol sym = locals.resolve(asg.variable()); if (sym == null || sym.kind() != SymbolKind.VARIABLE) { - ctx.getErrors().add(new SemanticError( - asg, - "未声明的变量: " + asg.variable() - )); + ctx.getErrors().add(new SemanticError(asg, + "未声明的变量: " + asg.variable())); ctx.log("错误: 未声明的变量 " + asg.variable()); return; } - // 2. 分析赋值表达式 - var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(asg.value()); - Type valType = exprAnalyzer.analyze(ctx, mi, fn, locals, asg.value()); + Type valType = ctx.getRegistry().getExpressionAnalyzer(asg.value()) + .analyze(ctx, mi, fn, locals, asg.value()); - // 3. 类型兼容性检查 if (!sym.type().isCompatible(valType)) { - ctx.getErrors().add(new SemanticError( - asg, - "赋值类型不匹配: 期望 " + sym.type() + ", 实际 " + valType - )); - ctx.log("错误: 赋值类型不匹配 " + asg.variable()); + // 数值宽化允许 + if (!(sym.type().isNumeric() && valType.isNumeric() + && Type.widen(valType, sym.type()) == sym.type())) { + ctx.getErrors().add(new SemanticError(asg, + "赋值类型不匹配: 期望 " + sym.type() + + ", 实际 " + valType)); + ctx.log("错误: 赋值类型不匹配 " + asg.variable()); + } } } } diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java index c0fb86e..5cc3151 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java @@ -6,85 +6,54 @@ import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer; import org.jcnc.snow.compiler.semantic.core.Context; import org.jcnc.snow.compiler.semantic.core.ModuleInfo; import org.jcnc.snow.compiler.semantic.error.SemanticError; -import org.jcnc.snow.compiler.semantic.symbol.Symbol; -import org.jcnc.snow.compiler.semantic.symbol.SymbolKind; -import org.jcnc.snow.compiler.semantic.symbol.SymbolTable; +import org.jcnc.snow.compiler.semantic.symbol.*; import org.jcnc.snow.compiler.semantic.type.BuiltinType; import org.jcnc.snow.compiler.semantic.type.Type; /** - * 变量声明语句分析器:负责对 {@link DeclarationNode} 节点进行语义检查。 - *

- * 分析流程: - *

    - *
  1. 解析声明类型,如果未知则记录错误并降级为 {@link BuiltinType#INT};
  2. - *
  3. 在当前符号表中注册新变量,若名称已存在则记录重复声明错误;
  4. - *
  5. 如存在初始化表达式,递归分析表达式并检查其类型与声明类型的兼容性;
  6. - *
  7. 兼容性检查失败时记录类型不匹配错误。
  8. - *
+ * 变量声明语句分析器:支持数值宽化自动转换和初始化检查。 */ public class DeclarationAnalyzer implements StatementAnalyzer { - - /** - * 对给定的声明节点进行语义分析。 - * - * @param ctx 全局上下文,包含模块表、错误收集、日志输出和分析器注册表等 - * @param mi 当前模块信息(在声明分析中未直接使用,但保留以便扩展) - * @param fn 当前函数节点(在声明分析中未直接使用,但可用于上下文检查) - * @param locals 当前作用域的符号表,用于注册新变量及类型查询 - * @param decl 待分析的 {@link DeclarationNode},包含变量名、声明类型及可选初始化表达式 - */ @Override public void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, DeclarationNode decl) { - // 1. 类型解析与降级 Type varType = ctx.parseType(decl.getType()); if (varType == null) { - ctx.getErrors().add(new SemanticError( - decl, - "未知类型: " + decl.getType() - )); - ctx.log("错误: 参数未知类型 " + decl.getType() - + " 在声明 " + decl.getName()); + ctx.getErrors().add(new SemanticError(decl, + "未知类型: " + decl.getType())); + ctx.log("错误: 未知类型 " + decl.getType() + + " 在声明 " + decl.getName()); varType = BuiltinType.INT; } ctx.log("声明变量: " + decl.getName() - + " 类型: " + varType); + + " 类型: " + varType); - // 2. 注册新变量,检查重复声明 if (!locals.define(new Symbol( - decl.getName(), - varType, - SymbolKind.VARIABLE + decl.getName(), varType, SymbolKind.VARIABLE ))) { - ctx.getErrors().add(new SemanticError( - decl, - "变量重复声明: " + decl.getName() - )); + ctx.getErrors().add(new SemanticError(decl, + "变量重复声明: " + decl.getName())); ctx.log("错误: 变量重复声明 " + decl.getName()); } - // 3. 初始化表达式类型检查 - Type declaredType = varType; + // 初始化表达式类型检查 + Type finalVarType = varType; decl.getInitializer().ifPresent(init -> { - var exprAnalyzer = ctx.getRegistry() - .getExpressionAnalyzer(init); - Type initType = exprAnalyzer.analyze( - ctx, mi, fn, locals, init - ); - if (!declaredType.isCompatible(initType)) { - ctx.getErrors().add(new SemanticError( - decl, - "初始化类型不匹配: 期望 " - + declaredType - + ", 实际 " - + initType - )); - ctx.log("错误: 初始化类型不匹配 " + Type initType = ctx.getRegistry().getExpressionAnalyzer(init) + .analyze(ctx, mi, fn, locals, init); + if (!finalVarType.isCompatible(initType)) { + // 数值宽化允许 + if (!(finalVarType.isNumeric() && initType.isNumeric() + && Type.widen(initType, finalVarType) == finalVarType)) { + ctx.getErrors().add(new SemanticError(decl, + "初始化类型不匹配: 期望 " + finalVarType + + ", 实际 " + initType)); + ctx.log("错误: 初始化类型不匹配 " + decl.getName()); + } } }); } diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java b/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java index e433c36..4f2c8b6 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java @@ -1,60 +1,73 @@ package org.jcnc.snow.compiler.semantic.type; /** - * 内置基础类型枚举:定义编译器中常见的基础类型。 + * 内置基础类型枚举:支持多种数值类型以及字符串和 void。 *

* 枚举值: *

    - *
  • {@link #INT} – 整数类型(32 位);
  • - *
  • {@link #LONG} – 长整数类型(64 位);
  • - *
  • {@link #SHORT} – 短整数类型(16 位);
  • - *
  • {@link #BYTE} – 字节类型(8 位);
  • - *
  • {@link #FLOAT} – 单精度浮点数;
  • - *
  • {@link #DOUBLE} – 双精度浮点数;
  • - *
  • {@link #STRING} – 字符串类型;
  • - *
  • {@link #VOID} – 空类型,用于表示无返回值的函数。
  • + *
  • {@link #BYTE} – 8 位整数
  • + *
  • {@link #SHORT} – 16 位整数
  • + *
  • {@link #INT} – 32 位整数
  • + *
  • {@link #LONG} – 64 位整数
  • + *
  • {@link #FLOAT} – 单精度浮点数
  • + *
  • {@link #DOUBLE} – 双精度浮点数
  • + *
  • {@link #STRING} – 字符串类型
  • + *
  • {@link #VOID} – 空类型,用于表示无返回值的函数
  • *
*

- * 本枚举实现了 {@link Type} 接口,提供了基本的类型兼容性判断和 - * 友好的字符串表示方法。 + * 本枚举实现了 {@link Type} 接口,提供了数值宽化和兼容性判断。 */ public enum BuiltinType implements Type { - /** 整数类型(32 位) */ - INT, - /** 长整数类型(64 位) */ - LONG, - /** 短整数类型(16 位) */ - SHORT, - /** 字节类型(8 位) */ BYTE, - /** 单精度浮点数 */ + SHORT, + INT, + LONG, FLOAT, - /** 双精度浮点数 */ DOUBLE, - /** 字符串类型 */ STRING, - /** 空类型,通常用于无返回值的函数 */ VOID; /** * 判断当前类型是否与另一个类型兼容。 *

- * 兼容条件:两个类型实例必须相同(同一枚举常量)。 + * 兼容条件: + *

    + *
  • 完全相同;
  • + *
  • 对于数值类型,允许自动宽化转换(narrow → wide)。
  • + *
* - * @param other 另一个需要检查兼容性的类型 - * @return 如果类型完全相同则返回 {@code true};否则返回 {@code false} + * @param other 另一个要检查的类型 + * @return 如果兼容返回 true,否则 false */ @Override public boolean isCompatible(Type other) { - return this == other; + if (this == other) return true; + // 如果两者都是数值类型,允许宽化 + if (this.isNumeric() && other.isNumeric()) { + return Type.widen(other, this) == this; + } + return false; } /** - * 返回小写形式的类型名称,便于输出和日志展示。 - *

- * 例如:{@link #INT} 返回 {@code "int"};{@link #VOID} 返回 {@code "void"}。 + * 判断是否为数值类型(byte、short、int、long、float、double)。 * - * @return 当前类型的小写字符串表示 + * @return 如果是数值类型返回 true,否则 false + */ + @Override + public boolean isNumeric() { + switch (this) { + case BYTE, SHORT, INT, LONG, FLOAT, DOUBLE: + return true; + default: + return false; + } + } + + /** + * 小写形式的类型名称,便于日志和错误输出。 + * + * @return 小写的类型名称 */ @Override public String toString() { diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java b/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java index d33c15d..7b37cad 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java @@ -1,3 +1,4 @@ +// File: src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java package org.jcnc.snow.compiler.semantic.type; /** @@ -7,16 +8,44 @@ package org.jcnc.snow.compiler.semantic.type; public interface Type { /** * 判断当前类型是否与另一个类型兼容。 - *

- * 例如: - *

    - *
  • 对于内置类型,只有完全相同的枚举常量才兼容;
  • - *
  • 对于函数类型,需要参数列表和返回类型同时兼容;
  • - *
  • 对于其他复合类型,可按语言规则自行实现。
  • - *
* * @param other 要检查兼容性的另一个类型 - * @return 如果兼容则返回 {@code true},否则返回 {@code false} + * @return 如果兼容则返回 true,否则返回 false */ boolean isCompatible(Type other); + + /** + * 判断当前类型是否为数值类型(byte/short/int/long/float/double)。 + *

+ * 默认实现返回 false,BuiltinType 会覆盖此方法。 + * + * @return 如果是数值类型则返回 true,否则返回 false + */ + default boolean isNumeric() { + return false; + } + + /** + * 对两个数值类型执行宽化转换,返回“更宽”的那个类型。 + *

+ * 若 a 和 b 都是数值类型,则按 byte→short→int→long→float→double 顺序选更宽的类型; + * 否则返回 null。 + * + * @param a 第一个类型 + * @param b 第二个类型 + * @return 两者中更宽的数值类型,或 null + */ + static Type widen(Type a, Type b) { + if (!(a.isNumeric() && b.isNumeric())) return null; + var order = java.util.List.of( + BuiltinType.BYTE, + BuiltinType.SHORT, + BuiltinType.INT, + BuiltinType.LONG, + BuiltinType.FLOAT, + BuiltinType.DOUBLE + ); + int ia = order.indexOf(a), ib = order.indexOf(b); + return order.get(Math.max(ia, ib)); + } } diff --git a/test b/test index d53221d..9026fa6 100644 --- a/test +++ b/test @@ -4,7 +4,7 @@ module: CommonTasks return num1 + num2 end body parameter: - declare num1: double + declare num1: int declare num2: int return_type: int end function @@ -93,7 +93,9 @@ module: MainModule declare sum: int = CommonTasks.add_numbers(i, 10) declare squared: int = MathUtils.square_number(sum) - BuiltinUtils.print(" i+10 squared = " + BuiltinUtils.to_string(squared)) + BuiltinUtils.print("i+10 squared = " + BuiltinUtils.to_string(squared)) + BuiltinUtils.print(1+1.1) + end body end loop