自动转换为string

This commit is contained in:
Luke 2025-04-28 14:43:39 +08:00
parent 379d1adfc7
commit 622d78b63c
7 changed files with 195 additions and 284 deletions

View File

@ -11,34 +11,9 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType;
import org.jcnc.snow.compiler.semantic.type.Type;
/**
* 二元表达式分析器负责对形如 <code>left op right</code> 的表达式进行类型推导和类型检查
* <p>
* 支持以下运算符
* <ul>
* <li><code>+</code>如果任一操作数为 {@link BuiltinType#STRING}则结果为字符串拼接否则如果都是整数则结果为整数</li>
* <li><code>-</code>, <code>*</code>, <code>/</code>, <code>%</code>要求两个操作数都是整数结果为整数</li>
* <li><code>&lt;</code>, <code>&lt;=</code>, <code>&gt;</code>, <code>&gt;=</code>, <code>==</code>, <code>!=</code>
* 要求两个操作数都是整数结果为整数表示真假</li>
* </ul>
* 对于未知运算符或类型不匹配的情况会在 {@link Context#getErrors() 错误列表} 中加入对应的
* {@link SemanticError}并将结果类型降级为 {@link BuiltinType#INT} 以避免后续连锁错误
* 二元表达式分析器支持数值宽化转换及字符串拼接
*/
public class BinaryExpressionAnalyzer implements ExpressionAnalyzer<BinaryExpressionNode> {
/**
* 对给定的二元表达式节点进行语义分析返回推导出的类型
*
* @param ctx 全局上下文包含模块表错误收集日志开关注册表等
* @param mi 当前正在分析的模块信息用于查找导入函数签名等
* @param fn 当前正在分析的函数节点用于处理返回类型检查等可用于更复杂场景
* @param locals 当前作用域的符号表包含已定义的局部变量及其类型
* @param bin 待分析的 {@link BinaryExpressionNode} 节点包含左子表达式运算符右子表达式
* @return 推导出的 {@link Type}
* <ul>
* <li>符合运算规则时返回 {@link BuiltinType#INT} {@link BuiltinType#STRING}</li>
* <li>类型不匹配或未知运算符时降级返回 {@link BuiltinType#INT}</li>
* </ul>
*/
@Override
public Type analyze(Context ctx,
ModuleInfo mi,
@ -47,64 +22,40 @@ public class BinaryExpressionAnalyzer implements ExpressionAnalyzer<BinaryExpres
BinaryExpressionNode bin) {
ctx.log("检查二元表达式: " + bin.operator());
// 递归分析左右两边的子表达式
var leftAnalyzer = ctx.getRegistry().getExpressionAnalyzer(bin.left());
Type left = leftAnalyzer.analyze(ctx, mi, fn, locals, bin.left());
var rightAnalyzer = ctx.getRegistry().getExpressionAnalyzer(bin.right());
Type right = rightAnalyzer.analyze(ctx, mi, fn, locals, bin.right());
// 递归获取左右子表达式类型
Type left = ctx.getRegistry().getExpressionAnalyzer(bin.left())
.analyze(ctx, mi, fn, locals, bin.left());
Type right = ctx.getRegistry().getExpressionAnalyzer(bin.right())
.analyze(ctx, mi, fn, locals, bin.right());
String op = bin.operator();
Type result;
// 根据运算符做类型推导
switch (op) {
case "+" -> {
// 字符串拼接 整数相加
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;
}
}
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);
// 数值运算或比较
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;
}
return wide;
}
}
// 如果推导失败类型不匹配记录错误并降级
if (result == null) {
// 未知或不支持的运算符/类型
ctx.getErrors().add(new SemanticError(
bin,
String.format("运算符 '%s' 不支持类型: %s 和 %s", op, left, right))
);
String.format("运算符 '%s' 不支持类型: %s 和 %s", op, left, right)
));
ctx.log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right);
result = BuiltinType.INT;
} else {
ctx.log("二元表达式推导类型: " + result);
}
return result;
return BuiltinType.INT;
}
}

View File

@ -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;
/**
* 函数调用表达式分析器负责对 <code>callee(arg1, arg2, ...)</code> 形式的调用进行
* 语义检查和类型推导
* <p>
* 支持两种调用方式
* 语义检查和类型推导并支持
* <ul>
* <li>模块函数调用<code>ModuleName.func(...)</code>要求模块已注册且已导入或与当前模块同名</li>
* <li>本模块函数调用<code>func(...)</code></li>
* <li>数值到字符串的隐式转换自动插入 to_string</li>
* <li>数值参数的宽化转换 int double</li>
* </ul>
* <p>
* 分析内容包括
* <ol>
* <li>解析目标模块与函数名</li>
* <li>检查函数是否已定义</li>
* <li>递归分析并收集所有实参的类型</li>
* <li>检查参数个数与参数类型是否与函数签名匹配</li>
* <li>返回函数签名中的返回类型</li>
* <li>在任何错误未知模块未导入模块调用方式不支持函数未定义
* 参数数量或类型不匹配记录对应的 {@link SemanticError}
* 并降级返回 {@link BuiltinType#INT} 以避免后续连锁错误</li>
* </ol>
*/
public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpressionNode> {
/**
* 对给定的调用表达式节点进行语义分析返回推导出的类型
*
* @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<CallExpression
SymbolTable locals,
CallExpressionNode call) {
ctx.log("检查函数调用: " + call.callee());
ModuleInfo target = mi;
String functionName;
// 解析 callee支持 Module.func(...) 本模块 func(...)
ExpressionNode callee = call.callee();
// 处理模块限定调用ModuleName.func(...)
if (callee instanceof MemberExpressionNode(var object, String member)) {
if (object instanceof IdentifierNode(String name)) {
if (!ctx.getModules().containsKey(name)
|| (!mi.getImports().contains(name) && !mi.getName().equals(name))) {
if (callee instanceof MemberExpressionNode(var obj, String member)
&& obj instanceof IdentifierNode(String mod)) {
if (!ctx.getModules().containsKey(mod)
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
ctx.getErrors().add(new SemanticError(callee,
"未知或未导入模块: " + name));
ctx.log("错误: 未导入模块 " + name);
"未知或未导入模块: " + mod));
ctx.log("错误: 未导入模块 " + mod);
return BuiltinType.INT;
}
target = ctx.getModules().get(name);
target = ctx.getModules().get(mod);
functionName = member;
ctx.log("调用模块函数: " + name + "." + member);
} else {
ctx.getErrors().add(new SemanticError(callee,
"不支持的调用方式: " + callee));
ctx.log("错误: 不支持的调用方式 " + callee);
return BuiltinType.INT;
}
// 处理本模块函数调用func(...)
} else if (callee instanceof IdentifierNode(String name)) {
functionName = name;
ctx.log("调用当前模块函数: " + functionName);
} else {
ctx.getErrors().add(new SemanticError(callee,
"不支持的调用方式: " + callee));
@ -105,38 +68,46 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
// 分析所有实参并收集类型
List<Type> 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)) {
// 完全兼容或宽化兼容
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);
}
}
}

View File

@ -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} 节点进行语义检查
* <p>
* 分析步骤
* <ol>
* <li>检查目标变量是否已在当前作用域中声明且种类为 {@link SymbolKind#VARIABLE}</li>
* <li>递归分析赋值右侧表达式获取其类型</li>
* <li>检查右侧表达式类型是否与目标变量类型兼容</li>
* <li>在任一检查失败时 {@link Context#getErrors() 错误列表} 中添加对应的
* {@link SemanticError} 并记录日志</li>
* </ol>
* 赋值语句分析器支持数值宽化自动转换
*/
public class AssignmentAnalyzer implements StatementAnalyzer<AssignmentNode> {
/**
* 对给定的赋值语句节点进行语义分析
*
* @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<AssignmentNode> {
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
));
// 数值宽化允许
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());
}
}
}
}

View File

@ -6,86 +6,55 @@ 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} 节点进行语义检查
* <p>
* 分析流程
* <ol>
* <li>解析声明类型如果未知则记录错误并降级为 {@link BuiltinType#INT}</li>
* <li>在当前符号表中注册新变量若名称已存在则记录重复声明错误</li>
* <li>如存在初始化表达式递归分析表达式并检查其类型与声明类型的兼容性</li>
* <li>兼容性检查失败时记录类型不匹配错误</li>
* </ol>
* 变量声明语句分析器支持数值宽化自动转换和初始化检查
*/
public class DeclarationAnalyzer implements StatementAnalyzer<DeclarationNode> {
/**
* 对给定的声明节点进行语义分析
*
* @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()
ctx.getErrors().add(new SemanticError(decl,
"未知类型: " + decl.getType()));
ctx.log("错误: 未知类型 " + decl.getType()
+ " 在声明 " + decl.getName());
varType = BuiltinType.INT;
}
ctx.log("声明变量: " + decl.getName()
+ " 类型: " + 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
));
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());
}
}
});
}
}

View File

@ -1,60 +1,73 @@
package org.jcnc.snow.compiler.semantic.type;
/**
* 内置基础类型枚举定义编译器中常见的基础类型
* 内置基础类型枚举支持多种数值类型以及字符串和 void
* <p>
* 枚举值
* <ul>
* <li>{@link #INT} 整数类型32 </li>
* <li>{@link #LONG} 长整数类型64 </li>
* <li>{@link #SHORT} 短整数类型16 </li>
* <li>{@link #BYTE} 字节类型8 </li>
* <li>{@link #FLOAT} 单精度浮点数</li>
* <li>{@link #DOUBLE} 双精度浮点数</li>
* <li>{@link #STRING} 字符串类型</li>
* <li>{@link #VOID} 空类型用于表示无返回值的函数</li>
* <li>{@link #BYTE} 8 位整数</li>
* <li>{@link #SHORT} 16 位整数</li>
* <li>{@link #INT} 32 位整数</li>
* <li>{@link #LONG} 64 位整数</li>
* <li>{@link #FLOAT} 单精度浮点数</li>
* <li>{@link #DOUBLE} 双精度浮点数</li>
* <li>{@link #STRING} 字符串类型</li>
* <li>{@link #VOID} 空类型用于表示无返回值的函数</li>
* </ul>
* <p>
* 本枚举实现了 {@link Type} 接口提供了基本的类型兼容性判断和
* 友好的字符串表示方法
* 本枚举实现了 {@link Type} 接口提供了数值宽化和兼容性判断
*/
public enum BuiltinType implements Type {
/** 整数类型32 位) */
INT,
/** 长整数类型64 位) */
LONG,
/** 短整数类型16 位) */
SHORT,
/** 字节类型8 位) */
BYTE,
/** 单精度浮点数 */
SHORT,
INT,
LONG,
FLOAT,
/** 双精度浮点数 */
DOUBLE,
/** 字符串类型 */
STRING,
/** 空类型,通常用于无返回值的函数 */
VOID;
/**
* 判断当前类型是否与另一个类型兼容
* <p>
* 兼容条件两个类型实例必须相同同一枚举常量
* 兼容条件
* <ul>
* <li>完全相同</li>
* <li>对于数值类型允许自动宽化转换narrow wide</li>
* </ul>
*
* @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;
}
/**
* 返回小写形式的类型名称便于输出和日志展示
* <p>
* 例如{@link #INT} 返回 {@code "int"}{@link #VOID} 返回 {@code "void"}
* 判断是否为数值类型byteshortintlongfloatdouble
*
* @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() {

View File

@ -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 {
/**
* 判断当前类型是否与另一个类型兼容
* <p>
* 例如
* <ul>
* <li>对于内置类型只有完全相同的枚举常量才兼容</li>
* <li>对于函数类型需要参数列表和返回类型同时兼容</li>
* <li>对于其他复合类型可按语言规则自行实现</li>
* </ul>
*
* @param other 要检查兼容性的另一个类型
* @return 如果兼容则返回 {@code true}否则返回 {@code false}
* @return 如果兼容则返回 true否则返回 false
*/
boolean isCompatible(Type other);
/**
* 判断当前类型是否为数值类型byte/short/int/long/float/double
* <p>
* 默认实现返回 falseBuiltinType 会覆盖此方法
*
* @return 如果是数值类型则返回 true否则返回 false
*/
default boolean isNumeric() {
return false;
}
/**
* 对两个数值类型执行宽化转换返回更宽的那个类型
* <p>
* a b 都是数值类型则按 byteshortintlongfloatdouble 顺序选更宽的类型
* 否则返回 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));
}
}

6
test
View File

@ -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