Add FunctionCall analysis
This commit is contained in:
parent
70aebb35a6
commit
1bfbd45c4a
@ -277,17 +277,25 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
|||||||
throw RuntimeError(ErrorType::NestedFunction, token.pos, {});
|
throw RuntimeError(ErrorType::NestedFunction, token.pos, {});
|
||||||
} catch (const InternalError& _) {}
|
} catch (const InternalError& _) {}
|
||||||
|
|
||||||
|
FunctionPrototype prototype = make_fn_prototype(node);
|
||||||
|
Type type = {
|
||||||
|
.type=TypeType::Function,
|
||||||
|
.data=prototype
|
||||||
|
};
|
||||||
|
|
||||||
if (memory.contains(function_name)) {
|
if (memory.contains(function_name)) {
|
||||||
// Il existe une variable non fonction à ce nom
|
// Il existe une variable non fonction à ce nom
|
||||||
if (memory.get(function_name).type.type != TypeType::Function) {
|
if (memory.get(function_name).type.type != TypeType::Function) {
|
||||||
throw RuntimeError(ErrorType::IncompatibleRedefinition, token.pos, function_name);
|
throw RuntimeError(ErrorType::IncompatibleRedefinition, token.pos, function_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type old_type = memory.get(function_name).type;
|
||||||
|
if (!equal_types(type, old_type)) {
|
||||||
|
throw TypeError(ErrorType::IncompatibleDefinition, token.pos, function_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory.declare(function_name, {
|
memory.declare(function_name, type, return_type_token.pos);
|
||||||
.type = TypeType::Function,
|
|
||||||
.data = make_fn_prototype(node)
|
|
||||||
}, return_type_token.pos);
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
} break;
|
} break;
|
||||||
@ -310,6 +318,10 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
|||||||
throw RuntimeError(ErrorType::FunctionRedefinition, token.pos, function_name);
|
throw RuntimeError(ErrorType::FunctionRedefinition, token.pos, function_name);
|
||||||
|
|
||||||
FunctionPrototype prototype = make_fn_prototype(node);
|
FunctionPrototype prototype = make_fn_prototype(node);
|
||||||
|
Type type = {
|
||||||
|
.type=TypeType::Function,
|
||||||
|
.data=prototype
|
||||||
|
};
|
||||||
|
|
||||||
if (memory.contains(function_name)) {
|
if (memory.contains(function_name)) {
|
||||||
// Il existe une variable non fonction à ce nom
|
// Il existe une variable non fonction à ce nom
|
||||||
@ -317,13 +329,13 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
|||||||
throw RuntimeError(ErrorType::IncompatibleRedefinition, token.pos, function_name);
|
throw RuntimeError(ErrorType::IncompatibleRedefinition, token.pos, function_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Vérification de la cohérence des arguments avec ceux du prototype
|
Type old_type = memory.get(function_name).type;
|
||||||
|
if (!equal_types(type, old_type)) {
|
||||||
|
throw TypeError(ErrorType::IncompatibleDefinition, token.pos, function_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory.declare(function_name, {
|
memory.declare(function_name, type, return_type_token.pos);
|
||||||
.type=TypeType::Function,
|
|
||||||
.data=prototype
|
|
||||||
}, return_type_token.pos);
|
|
||||||
|
|
||||||
memory.update(function_name, node.children[3]);
|
memory.update(function_name, node.children[3]);
|
||||||
|
|
||||||
@ -339,6 +351,24 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
|||||||
|
|
||||||
return {};
|
return {};
|
||||||
} break;
|
} break;
|
||||||
|
case NodeType::FunctionCall: {
|
||||||
|
Token token = get<Token>(node.children[0]);
|
||||||
|
string function_name = get<string>(token.data);
|
||||||
|
|
||||||
|
if (!memory.contains(function_name))
|
||||||
|
throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, function_name);
|
||||||
|
|
||||||
|
|
||||||
|
if (memory.contains(function_name) && !memory.get(function_name).initialized)
|
||||||
|
throw RuntimeError(ErrorType::UninitializedIdentifier, token.pos, function_name);
|
||||||
|
|
||||||
|
MemoryVar function = memory.get(function_name);
|
||||||
|
|
||||||
|
if (get<InnerNode>(node.children[1]).children.size() != get<FunctionPrototype>(function.type.data).size()-1)
|
||||||
|
throw RuntimeError(ErrorType::UnexpectedArgumentCount, token.pos, int(get<FunctionPrototype>(function.type.data).size())-1);
|
||||||
|
|
||||||
|
return get<0>(get<FunctionPrototype>(function.type.data).at(0));
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ string UserError::get_message(void) const {
|
|||||||
case ErrorType::NestedFunction: return "Function definition is not allowed here";
|
case ErrorType::NestedFunction: return "Function definition is not allowed here";
|
||||||
case ErrorType::FunctionRedefinition: return "Redefinition of '"+get<string>(this->data)+"'";
|
case ErrorType::FunctionRedefinition: return "Redefinition of '"+get<string>(this->data)+"'";
|
||||||
case ErrorType::IncompatibleRedefinition: return "Redefinition of '"+get<string>(this->data)+"' as different kind of symbol";
|
case ErrorType::IncompatibleRedefinition: return "Redefinition of '"+get<string>(this->data)+"' as different kind of symbol";
|
||||||
|
case ErrorType::IncompatibleDefinition: return "Declaration of '"+get<string>(this->data)+"' is incompatible with previous prototype";
|
||||||
|
case ErrorType::UnexpectedArgumentCount: return "Expected "+to_string(get<int>(this->data))+" arguments to function call";
|
||||||
case ErrorType::ExpectedArithmeticType: return "Expression must have arithmetic type";
|
case ErrorType::ExpectedArithmeticType: return "Expression must have arithmetic type";
|
||||||
case ErrorType::UnknownIdentifier: return "Unknown identifier '"+get<string>(this->data)+"'";
|
case ErrorType::UnknownIdentifier: return "Unknown identifier '"+get<string>(this->data)+"'";
|
||||||
case ErrorType::AlreadyDeclaredIdentifier: return "Already declared identifier '"+get<string>(this->data)+"'";
|
case ErrorType::AlreadyDeclaredIdentifier: return "Already declared identifier '"+get<string>(this->data)+"'";
|
||||||
|
@ -35,7 +35,9 @@ enum class ErrorType {
|
|||||||
ExpectedArithmeticType,
|
ExpectedArithmeticType,
|
||||||
NestedFunction,
|
NestedFunction,
|
||||||
FunctionRedefinition,
|
FunctionRedefinition,
|
||||||
IncompatibleRedefinition,
|
IncompatibleRedefinition, // redefinition of a variable as a function
|
||||||
|
IncompatibleDefinition, // function declaration incompatible with prototype
|
||||||
|
UnexpectedArgumentCount,
|
||||||
|
|
||||||
// Runtime
|
// Runtime
|
||||||
UnknownIdentifier,
|
UnknownIdentifier,
|
||||||
@ -48,7 +50,7 @@ enum class ErrorType {
|
|||||||
ControlReachesEndOfNonVoidFn
|
ControlReachesEndOfNonVoidFn
|
||||||
};
|
};
|
||||||
|
|
||||||
using ErrorData = variant<monostate, string>;
|
using ErrorData = variant<monostate, string, int>;
|
||||||
|
|
||||||
class UserError : public exception {
|
class UserError : public exception {
|
||||||
public:
|
public:
|
||||||
|
@ -34,4 +34,9 @@ vector<string> split_string(const string& input, char delimiter);
|
|||||||
*/
|
*/
|
||||||
string _debug_get_type_type_name(TypeType type);
|
string _debug_get_type_type_name(TypeType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if two types are equal
|
||||||
|
*/
|
||||||
|
bool equal_types(Type type1, Type type2);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -77,3 +77,38 @@ string _debug_get_type_type_name(TypeType type) {
|
|||||||
default: return "Unknown";
|
default: return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool equal_types(Type type1, Type type2) {
|
||||||
|
if (type1.type != type2.type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (type1.type) {
|
||||||
|
case TypeType::Int:
|
||||||
|
case TypeType::Double:
|
||||||
|
case TypeType::Void:
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case TypeType::Function: {
|
||||||
|
if (holds_alternative<monostate>(type1.data) != holds_alternative<monostate>(type2.data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (holds_alternative<monostate>(type1.data))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
FunctionPrototype args1 = get<FunctionPrototype>(type1.data);
|
||||||
|
FunctionPrototype args2 = get<FunctionPrototype>(type2.data);
|
||||||
|
|
||||||
|
if (args1.size() != args2.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i=0; i < (int)args1.size(); i++) {
|
||||||
|
if (!equal_types(get<0>(args1.at(i)), get<0>(args2.at(i))))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user