in lib/semantic.js [2680:2877]
getExprType(ast, env) {
if (!ast) {
return _basic('void');
}
if (ast.inferred) {
return ast.inferred;
}
if (ast.type === 'property_access' || ast.type === 'property') {
return this.calculatePropertyType(ast, env);
}
if (ast.type === 'map_access') {
let type;
if (ast.propertyPath) {
type = this.calculatePropertyType(ast, env);
} else {
type = this.getVariableType(ast.id, env);
}
if (type.type === 'array') {
return type.itemType;
} else if (type.type === 'map') {
return type.valueType;
}
}
if (ast.type === 'array_access') {
let type;
if (ast.propertyPath) {
type = this.calculatePropertyType(ast, env);
} else {
type = this.getVariableType(ast.id, env);
}
if (type.type === 'array') {
return type.itemType;
}
}
if (ast.type === 'string') {
return _basic('string');
}
if (ast.type === 'number') {
return _basic(ast.value.type);
}
if (ast.type === 'boolean') {
return _basic('boolean');
}
if (ast.type === 'object') {
if (ast.fields.length === 0) {
return {
type: 'map',
keyType: _basic('string'),
valueType: _basic('any')
};
}
var current;
var same = true;
for (let i = 0; i < ast.fields.length; i++) {
const field = ast.fields[i];
if (field.type === 'objectField') {
let type = this.getExprType(field.expr, env);
if (current && !isSameType(current, type)) {
same = false;
break;
}
current = type;
} else if (field.type === 'expandField') {
let type = this.getExprType(field.expr, env);
if (type.type === 'map') {
if (current && !isSameType(current, type.valueType)) {
same = false;
break;
}
current = type.valueType;
} else {
same = false;
break;
}
}
}
return {
type: 'map',
keyType: _basic('string'),
valueType: same ? current : _basic('any')
};
}
if (ast.type === 'variable') {
return this.getVariableType(ast.id, env);
}
if (ast.type === 'virtualVariable') {
const type = this.getInstanceProperty(ast.vid.lexeme);
return this.getType(type.value);
}
if (ast.type === 'null') {
return _basic('null');
}
if (ast.type === 'template_string') {
return _basic('string');
}
if (ast.type === 'call') {
assert.ok(ast.inferred);
return ast.inferred;
}
if (ast.type === 'super') {
return {
type: 'module_instance',
name: this.parentModuleId,
parentModuleIds: this.getParentModuleIds(this.parentModuleId),
};
}
if (ast.type === 'construct') {
return {
type: 'module_instance',
name: ast.aliasId.lexeme,
parentModuleIds: this.getParentModuleIds(ast.aliasId.lexeme),
};
}
if (ast.type === 'construct_model') {
if (ast.aliasId.isModel) {
const model = this.getModel([ast.aliasId.lexeme, ...ast.propertyPath.map((item) => {
return item.lexeme;
})].join('.'));
model.isException = ast.aliasId.isException;
return model;
}
const moduleName = ast.aliasId.lexeme;
const checker = this.dependencies.get(moduleName);
const model = checker.getModel(ast.propertyPath.map((item) => {
return item.lexeme;
}).join('.'), ast.aliasId.lexeme);
model.isException = ast.aliasId.isException;
return model;
}
if (ast.type === 'array') {
if (ast.items.length === 0) {
return {
type: 'array',
itemType: _basic('any')
};
}
let current;
let same = true;
for (let i = 0; i < ast.items.length; i++) {
const type = this.getExprType(ast.items[i], env);
if (current && !isSameType(current, type)) {
same = false;
break;
}
current = type;
}
return {
type: 'array',
itemType: same ? current : _basic('any')
};
}
if (ast.type === 'group') {
return this.getExprType(ast.expr, env);
}
if (isCompare(ast.type)) {
return _basic('boolean');
}
if (ast.type === 'and' || ast.type === 'or') {
return _basic('boolean');
}
if (ast.type === 'increment' || ast.type === 'decrement') {
return this.getExprType(ast.expr, env);
}
if (ast.type === 'add' || ast.type === 'subtract'
|| ast.type === 'div' || ast.type === 'multi') {
return this.getExprType(ast.right, env);
}
console.log(ast);
throw new Error('can not get type');
}