mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
chained assignments x=y=z=42
This commit is contained in:
parent
d91ca8b197
commit
6a639ce533
@ -25,7 +25,7 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep
|
||||
// - repeat-forever loops replaced by label+jump.
|
||||
// - pointer[word] replaced by @(pointer+word)
|
||||
// - @(&var) and @(&var+1) replaced by lsb(var) and msb(var) if var is a word
|
||||
|
||||
// - flatten chained assignments
|
||||
|
||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||
fun jumpAfter(stmt: Statement): Iterable<IAstModification> {
|
||||
@ -287,4 +287,21 @@ _after:
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(chainedAssignment: ChainedAssignment, parent: Node): Iterable<IAstModification> {
|
||||
val assign = chainedAssignment.nested as? Assignment
|
||||
if(assign!=null) {
|
||||
// unpack starting from last in the chain
|
||||
val assigns = mutableListOf<Statement>(assign)
|
||||
var lastChained: ChainedAssignment = chainedAssignment
|
||||
var pc: ChainedAssignment? = chainedAssignment
|
||||
while(pc!=null) {
|
||||
lastChained = pc
|
||||
assigns.add(0, Assignment(pc.target.copy(), assign.value.copy(), assign.origin, pc.position))
|
||||
pc = pc.parent as? ChainedAssignment
|
||||
}
|
||||
return listOf(IAstModification.ReplaceNode(lastChained,
|
||||
AnonymousScope(assigns, chainedAssignment.position), lastChained.parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
private fun transformStatement(statement: Statement): PtNode {
|
||||
return when (statement) {
|
||||
is AnonymousScope -> throw FatalAstException("AnonymousScopes should have been flattened")
|
||||
is ChainedAssignment -> throw FatalAstException("ChainedAssignment should have been flattened")
|
||||
is Assignment -> transform(statement)
|
||||
is Block -> transform(statement)
|
||||
is Break -> throw FatalAstException("break should have been replaced by Goto")
|
||||
|
@ -343,6 +343,12 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
}
|
||||
}
|
||||
|
||||
override fun visit(chainedAssignment: ChainedAssignment) {
|
||||
chainedAssignment.target.accept(this)
|
||||
output(" = ")
|
||||
chainedAssignment.nested.accept(this)
|
||||
}
|
||||
|
||||
override fun visit(postIncrDecr: PostIncrDecr) {
|
||||
postIncrDecr.target.accept(this)
|
||||
output(postIncrDecr.operator)
|
||||
|
@ -86,17 +86,11 @@ private fun StatementContext.toAst() : Statement {
|
||||
val vardecl = variabledeclaration()?.toAst()
|
||||
if(vardecl!=null) return vardecl
|
||||
|
||||
assignment()?.let {
|
||||
return Assignment(it.assign_target().toAst(), it.expression().toAst(), AssignmentOrigin.USERCODE, it.toPosition())
|
||||
}
|
||||
val assignment = assignment()?.toAst()
|
||||
if(assignment!=null) return assignment
|
||||
|
||||
augassignment()?.let {
|
||||
// replace A += X with A = A + X
|
||||
val target = it.assign_target().toAst()
|
||||
val oper = it.operator.text.substringBefore('=')
|
||||
val expression = BinaryExpression(target.toExpression(), oper, it.expression().toAst(), it.expression().toPosition())
|
||||
return Assignment(it.assign_target().toAst(), expression, AssignmentOrigin.USERCODE, it.toPosition())
|
||||
}
|
||||
val augassign = augassignment()?.toAst()
|
||||
if(augassign!=null) return augassign
|
||||
|
||||
postincrdecr()?.let {
|
||||
return PostIncrDecr(it.assign_target().toAst(), it.operator.text, it.toPosition())
|
||||
@ -338,6 +332,22 @@ private fun ClobberContext.toAst() : Set<CpuRegister> {
|
||||
}
|
||||
}
|
||||
|
||||
private fun AssignmentContext.toAst(): Statement {
|
||||
val nestedAssign = assignment()
|
||||
if(nestedAssign==null)
|
||||
return Assignment(assign_target().toAst(), expression().toAst(), AssignmentOrigin.USERCODE, toPosition())
|
||||
else
|
||||
return ChainedAssignment(assign_target().toAst(), nestedAssign.toAst(), toPosition())
|
||||
}
|
||||
|
||||
private fun AugassignmentContext.toAst(): Assignment {
|
||||
// replace A += X with A = A + X
|
||||
val target = assign_target().toAst()
|
||||
val oper = operator.text.substringBefore('=')
|
||||
val expression = BinaryExpression(target.toExpression(), oper, expression().toAst(), expression().toPosition())
|
||||
return Assignment(assign_target().toAst(), expression, AssignmentOrigin.USERCODE, toPosition())
|
||||
}
|
||||
|
||||
private fun DatatypeContext.toAst() = DataType.valueOf(text.uppercase())
|
||||
|
||||
private fun ArrayindexContext.toAst() : ArrayIndex =
|
||||
|
@ -354,12 +354,39 @@ enum class AssignmentOrigin {
|
||||
ASMGEN
|
||||
}
|
||||
|
||||
|
||||
class ChainedAssignment(var target: AssignTarget, var nested: Statement, override val position: Position): Statement() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
target.linkParents(this)
|
||||
nested.linkParents(this)
|
||||
}
|
||||
|
||||
override fun copy() = throw FatalAstException("you're not supposed to copy a ChainedAssignment")
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
when {
|
||||
node===target -> target = replacement as AssignTarget
|
||||
node===nested -> nested = replacement as Statement
|
||||
else -> throw FatalAstException("invalid replace")
|
||||
}
|
||||
replacement.parent = this
|
||||
}
|
||||
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
override fun toString() = "ChainedAssignment(target: $target, nested: $nested, pos=$position)"
|
||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean = target.referencesIdentifier(nameInSource) || nested.referencesIdentifier(nameInSource)
|
||||
}
|
||||
|
||||
class Assignment(var target: AssignTarget, var value: Expression, var origin: AssignmentOrigin, override val position: Position) : Statement() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
this.target.linkParents(this)
|
||||
target.linkParents(this)
|
||||
value.linkParents(this)
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,7 @@ abstract class AstWalker {
|
||||
open fun before(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(assignTarget: AssignTarget, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(chainedAssignment: ChainedAssignment, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(block: Block, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(branch: ConditionalBranch, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> = noModifications
|
||||
@ -140,6 +141,7 @@ abstract class AstWalker {
|
||||
open fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(assignTarget: AssignTarget, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(chainedAssignment: ChainedAssignment, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(block: Block, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(branch: ConditionalBranch, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(breakStmt: Break, parent: Node): Iterable<IAstModification> = noModifications
|
||||
@ -487,5 +489,12 @@ abstract class AstWalker {
|
||||
whenChoice.statements.accept(this, whenChoice)
|
||||
track(after(whenChoice, parent), whenChoice, parent)
|
||||
}
|
||||
|
||||
fun visit(chainedAssignment: ChainedAssignment, parent: Node) {
|
||||
track(before(chainedAssignment, parent), chainedAssignment, parent)
|
||||
chainedAssignment.target.accept(this, chainedAssignment)
|
||||
chainedAssignment.nested.accept(this, chainedAssignment)
|
||||
track(after(chainedAssignment, parent), chainedAssignment, parent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,4 +191,9 @@ interface IAstVisitor {
|
||||
whenChoice.values?.forEach { it.accept(this) }
|
||||
whenChoice.statements.accept(this)
|
||||
}
|
||||
|
||||
fun visit(chainedAssignment: ChainedAssignment) {
|
||||
chainedAssignment.target.accept(this)
|
||||
chainedAssignment.nested.accept(this)
|
||||
}
|
||||
}
|
||||
|
@ -624,6 +624,9 @@ Only variables of type byte, word and float can be assigned a new value.
|
||||
It's not possible to set a new value to string or array variables etc, because they get allocated
|
||||
a fixed amount of memory which will not change. (You *can* change the value of elements in a string or array though).
|
||||
|
||||
It is possible to "chain" assignments: ``x = y = z = 42``, this is just a shorthand
|
||||
for the three individual assignments with the same value 42.
|
||||
|
||||
.. attention::
|
||||
**Data type conversion (in assignments):**
|
||||
When assigning a value with a 'smaller' datatype to variable with a 'larger' datatype,
|
||||
|
@ -555,6 +555,7 @@ bitwise arithmetic: ``&`` ``|`` ``^`` ``~`` ``<<`` ``>>``
|
||||
assignment: ``=``
|
||||
Sets the target on the LHS (left hand side) of the operator to the value of the expression on the RHS (right hand side).
|
||||
Note that an assignment sometimes is not possible or supported.
|
||||
It's possible to chain assignments like ``x = y = z = 42`` as a shorthand for the three assignments with the same value.
|
||||
|
||||
augmented assignment: ``+=`` ``-=`` ``*=`` ``/=`` ``&=`` ``|=`` ``^=`` ``<<=`` ``>>=``
|
||||
This is syntactic sugar; ``aa += xx`` is equivalent to ``aa = aa + xx``
|
||||
|
@ -78,7 +78,6 @@ What if we were to re-introduce Structs in prog8? Some thoughts:
|
||||
Other language/syntax features to think about
|
||||
---------------------------------------------
|
||||
|
||||
- chained assignments `x=y=z=99`
|
||||
- declare multiple variables `ubyte x,y,z` (if init value present, all get that init value)
|
||||
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`)
|
||||
- postincrdecr as expression, preincrdecr expression (`y = x++`, `y = ++x`) .... is this even possible, expression with side effects like this?
|
||||
|
@ -2,7 +2,21 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
const ubyte VAL = 11
|
||||
sub start() {
|
||||
uword w
|
||||
ubyte x
|
||||
ubyte y
|
||||
ubyte z
|
||||
|
||||
w = x = y = z = 99+VAL
|
||||
txt.print_ub(x)
|
||||
txt.spc()
|
||||
txt.print_ub(y)
|
||||
txt.spc()
|
||||
txt.print_ub(z)
|
||||
txt.spc()
|
||||
txt.print_uw(w)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'bool' ;
|
||||
|
||||
arrayindex: '[' expression ']' ;
|
||||
|
||||
assignment : assign_target '=' expression ;
|
||||
assignment : (assign_target '=' expression) | (assign_target '=' assignment);
|
||||
|
||||
augassignment :
|
||||
assign_target operator=('+=' | '-=' | '/=' | '*=' | '&=' | '|=' | '^=' | '%=' | '<<=' | '>>=' ) expression
|
||||
|
Loading…
x
Reference in New Issue
Block a user