Skip to content

Commit

Permalink
Language Server - parseVariable initializations (#27)
Browse files Browse the repository at this point in the history
( from https://kolmafia.us/threads/ash-language-server-features.26098/post-163766 )
A bit more complex than the last few; this patch modifies parseVariable so that the signal indicating that we're parsing parameters is a boolean, rather than scope being null, and waits until the end to throw the error.
This, again, will allow us to still keep trying to parse a parameter initialization, and will give us a full location once we throw the error.

Also shuffles the parsing logic a little, for efficiency.

* not supposed to touch that one either..?
Why'd the test work anyway, then..?
(context: d353d73)

* way to pass the variable name (and location, in the future!)
  • Loading branch information
fredg1 committed Sep 27, 2021
1 parent 78c24b6 commit 16568f1
Showing 1 changed file with 54 additions and 42 deletions.
96 changes: 54 additions & 42 deletions src/net/sourceforge/kolmafia/textui/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,11 @@ else if ( !paramList.add( param ) )
throw this.parseException( "Parameter " + param.getName() + " is already defined" );
}

if ( this.currentToken().equals( "=" ) )
{
throw this.parseException( "Cannot initialize parameter " + param.getName() );
}

if ( paramType instanceof VarArgType )
{
// Only one vararg is allowed
Expand Down Expand Up @@ -836,6 +841,31 @@ private boolean parseVariables( final Type t, final BasicScope parentScope )
return false;
}

parentScope.addVariable( v );
VariableReference lhs = new VariableReference( v );
Value rhs;

if ( this.currentToken().equals( "=" ) )
{
this.readToken(); //read =

rhs = this.parseInitialization( lhs, parentScope );
}
else if ( this.currentToken().equals( "{" ) )
{
// We allow two ways of initializing aggregates:
// <aggregate type> <name> = {};
// <aggregate type> <name> {};

rhs = this.parseInitialization( lhs, parentScope );
}
else
{
rhs = null;
}

parentScope.addCommand( new Assignment( lhs, rhs ), this );

if ( this.currentToken().equals( "," ) )
{
this.readToken(); //read ,
Expand Down Expand Up @@ -869,68 +899,50 @@ else if ( scope != null && scope.findVariable( variableName.content ) != null )
result = new Variable( variableName.content, t );
}

this.readToken(); // If parsing of Identifier succeeded, go to next token.
// If we are parsing a parameter declaration, we are done
if ( scope == null )
{
if ( this.currentToken().equals( "=" ) )
{
throw this.parseException( "Cannot initialize parameter " + variableName );
}
return result;
}
this.readToken(); // read name

// Otherwise, we must initialize the variable.
return result;
}

Value rhs;
/**
* Parses the right-hand-side of a variable definition. It is assumed that the caller expects
* an expression to be found, so this method never returns null.
*/
private Value parseInitialization( final VariableReference lhs, final BasicScope scope )
{
Value result;

Type t = lhs.target.getType();
Type ltype = t.getBaseType();
if ( this.currentToken().equals( "=" ) )
if ( this.currentToken().equals( "{" ) )
{
this.readToken(); // read =

if ( this.currentToken().equals( "{" ) )
if ( ltype instanceof AggregateType )
{
if ( ltype instanceof AggregateType )
{
rhs = this.parseAggregateLiteral( scope, (AggregateType) ltype );
}
else
{
throw this.parseException(
"Cannot initialize " + variableName + " of type " + t + " with an aggregate literal" );
}
result = this.parseAggregateLiteral( scope, (AggregateType) ltype );
}
else
{
rhs = this.parseExpression( scope );
throw this.parseException(
"Cannot initialize " + lhs + " of type " + t + " with an aggregate literal" );
}
}
else
{
result = this.parseExpression( scope );

if ( rhs != null )
if ( result != null )
{
rhs = this.autoCoerceValue( t, rhs, scope );
if ( !Operator.validCoercion( ltype, rhs.getType(), "assign" ) )
result = this.autoCoerceValue( t, result, scope );
if ( !Operator.validCoercion( ltype, result.getType(), "assign" ) )
{
throw this.parseException( "Cannot store " + rhs.getType() + " in " + variableName + " of type " + ltype );
throw this.parseException( "Cannot store " + result.getType() + " in " + lhs + " of type " + ltype );
}
}
else
{
throw this.parseException( "Expression expected" );
}
}
else if ( this.currentToken().equals( "{" ) && ltype instanceof AggregateType )
{
rhs = this.parseAggregateLiteral( scope, (AggregateType) ltype );
}
else
{
rhs = null;
}

scope.addVariable( result );
VariableReference lhs = new VariableReference( variableName.content, scope );
scope.addCommand( new Assignment( lhs, rhs ), this );

return result;
}
Expand Down

0 comments on commit 16568f1

Please sign in to comment.