mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parse types in Julia mode
This commit is contained in:
parent
b0f2a5c162
commit
d6396ee85f
@ -184,7 +184,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
|||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
bool success = boost::apply_visitor(*this, *_varDecl.value);
|
bool success = boost::apply_visitor(*this, *_varDecl.value);
|
||||||
solAssert(m_stackHeight - stackHeight == 1, "Invalid value size.");
|
solAssert(m_stackHeight - stackHeight == 1, "Invalid value size.");
|
||||||
boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.name)).active = true;
|
boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.variable.name)).active = true;
|
||||||
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
|
|||||||
{
|
{
|
||||||
Scope& bodyScope = scope(&_funDef.body);
|
Scope& bodyScope = scope(&_funDef.body);
|
||||||
for (auto const& var: _funDef.arguments + _funDef.returns)
|
for (auto const& var: _funDef.arguments + _funDef.returns)
|
||||||
boost::get<Scope::Variable>(bodyScope.identifiers.at(var)).active = true;
|
boost::get<Scope::Variable>(bodyScope.identifiers.at(var.name)).active = true;
|
||||||
|
|
||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
|
m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
|
||||||
@ -232,8 +232,9 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
|
|||||||
},
|
},
|
||||||
[&](Scope::Function const& _fun)
|
[&](Scope::Function const& _fun)
|
||||||
{
|
{
|
||||||
arguments = _fun.arguments;
|
/// TODO: compare types too
|
||||||
returns = _fun.returns;
|
arguments = _fun.arguments.size();
|
||||||
|
returns = _fun.returns.size();
|
||||||
}
|
}
|
||||||
)))
|
)))
|
||||||
{
|
{
|
||||||
|
@ -204,7 +204,7 @@ public:
|
|||||||
int height = m_state.assembly.deposit();
|
int height = m_state.assembly.deposit();
|
||||||
boost::apply_visitor(*this, *_varDecl.value);
|
boost::apply_visitor(*this, *_varDecl.value);
|
||||||
expectDeposit(1, height);
|
expectDeposit(1, height);
|
||||||
auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.name));
|
auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.variable.name));
|
||||||
var.stackHeight = height;
|
var.stackHeight = height;
|
||||||
var.active = true;
|
var.active = true;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,17 @@ namespace solidity
|
|||||||
namespace assembly
|
namespace assembly
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using Type = std::string;
|
||||||
|
|
||||||
|
struct TypedName { SourceLocation location; std::string name; Type type; };
|
||||||
|
using TypedNameList = std::vector<TypedName>;
|
||||||
|
|
||||||
/// What follows are the AST nodes for assembly.
|
/// What follows are the AST nodes for assembly.
|
||||||
|
|
||||||
/// Direct EVM instruction (except PUSHi and JUMPDEST)
|
/// Direct EVM instruction (except PUSHi and JUMPDEST)
|
||||||
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
|
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
|
||||||
/// Literal number or string (up to 32 bytes)
|
/// Literal number or string (up to 32 bytes)
|
||||||
struct Literal { SourceLocation location; bool isNumber; std::string value; };
|
struct Literal { SourceLocation location; bool isNumber; std::string value; Type type; };
|
||||||
/// External / internal identifier or label reference
|
/// External / internal identifier or label reference
|
||||||
struct Identifier { SourceLocation location; std::string name; };
|
struct Identifier { SourceLocation location; std::string name; };
|
||||||
struct FunctionalInstruction;
|
struct FunctionalInstruction;
|
||||||
@ -52,18 +57,18 @@ struct FunctionDefinition;
|
|||||||
struct FunctionCall;
|
struct FunctionCall;
|
||||||
struct Block;
|
struct Block;
|
||||||
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>;
|
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>;
|
||||||
/// Functional assignment ("x := mload(20)", expects push-1-expression on the right hand
|
/// Functional assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
|
||||||
/// side and requires x to occupy exactly one stack slot.
|
/// side and requires x to occupy exactly one stack slot.
|
||||||
struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
|
struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
|
||||||
/// Functional instruction, e.g. "mul(mload(20), add(2, x))"
|
/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))"
|
||||||
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
|
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
|
||||||
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
|
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
|
||||||
/// Block-scope variable declaration ("let x := mload(20)"), non-hoisted
|
/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
|
||||||
struct VariableDeclaration { SourceLocation location; std::string name; std::shared_ptr<Statement> value; };
|
struct VariableDeclaration { SourceLocation location; TypedName variable; std::shared_ptr<Statement> value; };
|
||||||
/// Block that creates a scope (frees declared stack variables)
|
/// Block that creates a scope (frees declared stack variables)
|
||||||
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
||||||
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
||||||
struct FunctionDefinition { SourceLocation location; std::string name; std::vector<std::string> arguments; std::vector<std::string> returns; Block body; };
|
struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList arguments; TypedNameList returns; Block body; };
|
||||||
|
|
||||||
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
||||||
{
|
{
|
||||||
|
@ -201,16 +201,26 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = Identifier{location(), literal};
|
ret = Identifier{location(), literal};
|
||||||
|
m_scanner->next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Token::StringLiteral:
|
case Token::StringLiteral:
|
||||||
case Token::Number:
|
case Token::Number:
|
||||||
{
|
{
|
||||||
ret = Literal{
|
Literal literal{
|
||||||
location(),
|
location(),
|
||||||
m_scanner->currentToken() == Token::Number,
|
m_scanner->currentToken() == Token::Number,
|
||||||
m_scanner->currentLiteral()
|
m_scanner->currentLiteral(),
|
||||||
|
""
|
||||||
};
|
};
|
||||||
|
m_scanner->next();
|
||||||
|
if (m_julia)
|
||||||
|
{
|
||||||
|
expectToken(Token::Colon);
|
||||||
|
literal.location.end = endPosition();
|
||||||
|
literal.type = expectAsmIdentifier();
|
||||||
|
}
|
||||||
|
ret = std::move(literal);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -220,7 +230,6 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
|||||||
"Expected elementary inline assembly operation."
|
"Expected elementary inline assembly operation."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
m_scanner->next();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +237,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
{
|
{
|
||||||
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
||||||
expectToken(Token::Let);
|
expectToken(Token::Let);
|
||||||
varDecl.name = expectAsmIdentifier();
|
varDecl.variable = parseTypedName();
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
expectToken(Token::Assign);
|
expectToken(Token::Assign);
|
||||||
varDecl.value.reset(new Statement(parseExpression()));
|
varDecl.value.reset(new Statement(parseExpression()));
|
||||||
@ -244,7 +253,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
|||||||
expectToken(Token::LParen);
|
expectToken(Token::LParen);
|
||||||
while (m_scanner->currentToken() != Token::RParen)
|
while (m_scanner->currentToken() != Token::RParen)
|
||||||
{
|
{
|
||||||
funDef.arguments.push_back(expectAsmIdentifier());
|
funDef.arguments.emplace_back(parseTypedName());
|
||||||
if (m_scanner->currentToken() == Token::RParen)
|
if (m_scanner->currentToken() == Token::RParen)
|
||||||
break;
|
break;
|
||||||
expectToken(Token::Comma);
|
expectToken(Token::Comma);
|
||||||
@ -256,7 +265,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
|||||||
expectToken(Token::GreaterThan);
|
expectToken(Token::GreaterThan);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
funDef.returns.push_back(expectAsmIdentifier());
|
funDef.returns.emplace_back(parseTypedName());
|
||||||
if (m_scanner->currentToken() == Token::LBrace)
|
if (m_scanner->currentToken() == Token::LBrace)
|
||||||
break;
|
break;
|
||||||
expectToken(Token::Comma);
|
expectToken(Token::Comma);
|
||||||
@ -335,6 +344,19 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypedName Parser::parseTypedName()
|
||||||
|
{
|
||||||
|
TypedName typedName = createWithLocation<TypedName>();
|
||||||
|
typedName.name = expectAsmIdentifier();
|
||||||
|
if (m_julia)
|
||||||
|
{
|
||||||
|
expectToken(Token::Colon);
|
||||||
|
typedName.location.end = endPosition();
|
||||||
|
typedName.type = expectAsmIdentifier();
|
||||||
|
}
|
||||||
|
return typedName;
|
||||||
|
}
|
||||||
|
|
||||||
string Parser::expectAsmIdentifier()
|
string Parser::expectAsmIdentifier()
|
||||||
{
|
{
|
||||||
string name = m_scanner->currentLiteral();
|
string name = m_scanner->currentLiteral();
|
||||||
|
@ -69,6 +69,7 @@ protected:
|
|||||||
VariableDeclaration parseVariableDeclaration();
|
VariableDeclaration parseVariableDeclaration();
|
||||||
FunctionDefinition parseFunctionDefinition();
|
FunctionDefinition parseFunctionDefinition();
|
||||||
Statement parseFunctionalInstruction(Statement&& _instruction);
|
Statement parseFunctionalInstruction(Statement&& _instruction);
|
||||||
|
TypedName parseTypedName();
|
||||||
std::string expectAsmIdentifier();
|
std::string expectAsmIdentifier();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -47,7 +47,7 @@ string AsmPrinter::operator()(assembly::Instruction const& _instruction)
|
|||||||
string AsmPrinter::operator()(assembly::Literal const& _literal)
|
string AsmPrinter::operator()(assembly::Literal const& _literal)
|
||||||
{
|
{
|
||||||
if (_literal.isNumber)
|
if (_literal.isNumber)
|
||||||
return _literal.value;
|
return _literal.value + appendTypeName(_literal.type);
|
||||||
string out;
|
string out;
|
||||||
for (char c: _literal.value)
|
for (char c: _literal.value)
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
@ -74,7 +74,7 @@ string AsmPrinter::operator()(assembly::Literal const& _literal)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
out += c;
|
out += c;
|
||||||
return "\"" + out + "\"";
|
return "\"" + out + "\"" + appendTypeName(_literal.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(assembly::Identifier const& _identifier)
|
string AsmPrinter::operator()(assembly::Identifier const& _identifier)
|
||||||
@ -113,14 +113,22 @@ string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalA
|
|||||||
|
|
||||||
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
|
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
|
||||||
{
|
{
|
||||||
return "let " + _variableDeclaration.name + " := " + boost::apply_visitor(*this, *_variableDeclaration.value);
|
return "let " + _variableDeclaration.variable.name + appendTypeName(_variableDeclaration.variable.type) + " := " + boost::apply_visitor(*this, *_variableDeclaration.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
|
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
|
||||||
{
|
{
|
||||||
string out = "function " + _functionDefinition.name + "(" + boost::algorithm::join(_functionDefinition.arguments, ", ") + ")";
|
string out = "function " + _functionDefinition.name + "(";
|
||||||
|
for (auto const& argument: _functionDefinition.arguments)
|
||||||
|
out += argument.name + appendTypeName(argument.type) + ",";
|
||||||
|
out += ")";
|
||||||
if (!_functionDefinition.returns.empty())
|
if (!_functionDefinition.returns.empty())
|
||||||
out += " -> " + boost::algorithm::join(_functionDefinition.returns, ", ");
|
{
|
||||||
|
out += " -> ";
|
||||||
|
for (auto const& argument: _functionDefinition.returns)
|
||||||
|
out += argument.name + appendTypeName(argument.type) + ",";
|
||||||
|
}
|
||||||
|
|
||||||
return out + "\n" + (*this)(_functionDefinition.body);
|
return out + "\n" + (*this)(_functionDefinition.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,3 +153,10 @@ string AsmPrinter::operator()(Block const& _block)
|
|||||||
boost::replace_all(body, "\n", "\n ");
|
boost::replace_all(body, "\n", "\n ");
|
||||||
return "{\n " + body + "\n}";
|
return "{\n " + body + "\n}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AsmPrinter::appendTypeName(std::string const& _type)
|
||||||
|
{
|
||||||
|
if (m_julia)
|
||||||
|
return ":" + _type;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
@ -60,6 +60,8 @@ public:
|
|||||||
std::string operator()(assembly::Block const& _block);
|
std::string operator()(assembly::Block const& _block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string appendTypeName(std::string const& _type);
|
||||||
|
|
||||||
bool m_julia = false;
|
bool m_julia = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,15 +32,17 @@ bool Scope::registerLabel(string const& _name)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scope::registerVariable(string const& _name)
|
bool Scope::registerVariable(string const& _name, JuliaType const& _type)
|
||||||
{
|
{
|
||||||
if (exists(_name))
|
if (exists(_name))
|
||||||
return false;
|
return false;
|
||||||
identifiers[_name] = Variable();
|
Variable variable;
|
||||||
|
variable.type = _type;
|
||||||
|
identifiers[_name] = variable;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scope::registerFunction(string const& _name, size_t _arguments, size_t _returns)
|
bool Scope::registerFunction(string const& _name, std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns)
|
||||||
{
|
{
|
||||||
if (exists(_name))
|
if (exists(_name))
|
||||||
return false;
|
return false;
|
||||||
|
@ -61,6 +61,8 @@ struct GenericVisitor<>: public boost::static_visitor<> {
|
|||||||
|
|
||||||
struct Scope
|
struct Scope
|
||||||
{
|
{
|
||||||
|
using JuliaType = std::string;
|
||||||
|
|
||||||
struct Variable
|
struct Variable
|
||||||
{
|
{
|
||||||
/// Used during code generation to store the stack height. @todo move there.
|
/// Used during code generation to store the stack height. @todo move there.
|
||||||
@ -68,6 +70,7 @@ struct Scope
|
|||||||
/// Used during analysis to check whether we already passed the declaration inside the block.
|
/// Used during analysis to check whether we already passed the declaration inside the block.
|
||||||
/// @todo move there.
|
/// @todo move there.
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
JuliaType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Label
|
struct Label
|
||||||
@ -78,18 +81,22 @@ struct Scope
|
|||||||
|
|
||||||
struct Function
|
struct Function
|
||||||
{
|
{
|
||||||
Function(size_t _arguments, size_t _returns): arguments(_arguments), returns(_returns) {}
|
Function(std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns): arguments(_arguments), returns(_returns) {}
|
||||||
size_t arguments = 0;
|
std::vector<JuliaType> arguments;
|
||||||
size_t returns = 0;
|
std::vector<JuliaType> returns;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Identifier = boost::variant<Variable, Label, Function>;
|
using Identifier = boost::variant<Variable, Label, Function>;
|
||||||
using Visitor = GenericVisitor<Variable const, Label const, Function const>;
|
using Visitor = GenericVisitor<Variable const, Label const, Function const>;
|
||||||
using NonconstVisitor = GenericVisitor<Variable, Label, Function>;
|
using NonconstVisitor = GenericVisitor<Variable, Label, Function>;
|
||||||
|
|
||||||
bool registerVariable(std::string const& _name);
|
bool registerVariable(std::string const& _name, JuliaType const& _type);
|
||||||
bool registerLabel(std::string const& _name);
|
bool registerLabel(std::string const& _name);
|
||||||
bool registerFunction(std::string const& _name, size_t _arguments, size_t _returns);
|
bool registerFunction(
|
||||||
|
std::string const& _name,
|
||||||
|
std::vector<JuliaType> const& _arguments,
|
||||||
|
std::vector<JuliaType> const& _returns
|
||||||
|
);
|
||||||
|
|
||||||
/// Looks up the identifier in this or super scopes and returns a valid pointer if found
|
/// Looks up the identifier in this or super scopes and returns a valid pointer if found
|
||||||
/// or a nullptr if not found. Variable lookups up across function boundaries will fail, as
|
/// or a nullptr if not found. Variable lookups up across function boundaries will fail, as
|
||||||
|
@ -59,13 +59,19 @@ bool ScopeFiller::operator()(Label const& _item)
|
|||||||
|
|
||||||
bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl)
|
bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
return registerVariable(_varDecl.name, _varDecl.location, *m_currentScope);
|
return registerVariable(_varDecl.variable, _varDecl.location, *m_currentScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
|
bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (!m_currentScope->registerFunction(_funDef.name, _funDef.arguments.size(), _funDef.returns.size()))
|
vector<Scope::JuliaType> arguments;
|
||||||
|
for (auto const& _argument: _funDef.arguments)
|
||||||
|
arguments.push_back(_argument.type);
|
||||||
|
vector<Scope::JuliaType> returns;
|
||||||
|
for (auto const& _return: _funDef.returns)
|
||||||
|
returns.push_back(_return.type);
|
||||||
|
if (!m_currentScope->registerFunction(_funDef.name, arguments, returns))
|
||||||
{
|
{
|
||||||
//@TODO secondary location
|
//@TODO secondary location
|
||||||
m_errors.push_back(make_shared<Error>(
|
m_errors.push_back(make_shared<Error>(
|
||||||
@ -102,14 +108,14 @@ bool ScopeFiller::operator()(Block const& _block)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScopeFiller::registerVariable(string const& _name, SourceLocation const& _location, Scope& _scope)
|
bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& _location, Scope& _scope)
|
||||||
{
|
{
|
||||||
if (!_scope.registerVariable(_name))
|
if (!_scope.registerVariable(_name.name, _name.type))
|
||||||
{
|
{
|
||||||
//@TODO secondary location
|
//@TODO secondary location
|
||||||
m_errors.push_back(make_shared<Error>(
|
m_errors.push_back(make_shared<Error>(
|
||||||
Error::Type::DeclarationError,
|
Error::Type::DeclarationError,
|
||||||
"Variable name " + _name + " already taken in this scope.",
|
"Variable name " + _name.name + " already taken in this scope.",
|
||||||
_location
|
_location
|
||||||
));
|
));
|
||||||
return false;
|
return false;
|
||||||
|
@ -34,6 +34,7 @@ namespace solidity
|
|||||||
namespace assembly
|
namespace assembly
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct TypedName;
|
||||||
struct Literal;
|
struct Literal;
|
||||||
struct Block;
|
struct Block;
|
||||||
struct Label;
|
struct Label;
|
||||||
@ -72,7 +73,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool registerVariable(
|
bool registerVariable(
|
||||||
std::string const& _name,
|
TypedName const& _name,
|
||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
Scope& _scope
|
Scope& _scope
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user