Skip to content
This repository has been archived by the owner on Sep 28, 2022. It is now read-only.

Commit

Permalink
Adds simple destructuring.
Browse files Browse the repository at this point in the history
Allows to destructure a object to assign to several values at the same
time. E.g.:

    let a, b = [1, 2]
    require(a == 1 and b == 2, "failed")

Any object with a `destruct` method returning a tuple can be used.
Vararg can be used as the last value, e.g.

    let a, b... = [1, 2, 3, 4]
    require(a == 1 and b == [2, 3, 4], "failed")

Some built-in objects and augmentation are added to be compliant.
  • Loading branch information
yloiseau committed Jul 6, 2015
1 parent 65a8fe2 commit 2f1dc71
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/main/golo/standard-augmentations.golo
Expand Up @@ -496,6 +496,13 @@ augment java.util.List {
needed since for Golo everything is an `Object` and `remove` is overloaded.
----
function removeAt = |this, idx| -> removeByIndex(this, idx)

----
Destructuration helper.
* return a tuple of the values
----
function destruct = |this| -> Tuple.fromArray(this: toArray())
}

# ............................................................................................... #
Expand Down
Expand Up @@ -528,6 +528,41 @@ public Object visit(ASTAssignment node, Object data) {
return data;
}

@Override
public Object visit(ASTDestructuringAssignment node, Object data) {
Context context = (Context) data;
ReferenceTable localTable = context.referenceTableStack.peek().fork();
Block block = new Block(localTable);
String varName = "__$$_destruct_" + System.currentTimeMillis();
LocalReference destructReference = new LocalReference(CONSTANT, varName, true);
localTable.add(destructReference);

node.jjtGetChild(0).jjtAccept(this, data);
ExpressionStatement destructExpressionStatement = (ExpressionStatement) context.objectStack.pop();
AssignmentStatement init = new AssignmentStatement(destructReference,
new BinaryOperation(OperatorType.METHOD_CALL,
destructExpressionStatement,
new MethodInvocation("destruct")));
init.setDeclaring(true);
init.setASTNode(node);
block.addStatement(init);
int idx = 0;
int last = node.getNames().size() - 1;
for (String name : node.getNames()) {
LocalReference val = new LocalReference(node.getType() == LET ? CONSTANT : VARIABLE, name, true);
MethodInvocation get = new MethodInvocation(!node.isVarargs() || idx != last ? "get" : "subTuple");
get.addArgument(new ConstantStatement(idx));
context.referenceTableStack.peek().add(val);
AssignmentStatement valInit = new AssignmentStatement(val,
new BinaryOperation(OperatorType.METHOD_CALL,
new ReferenceLookup(varName), get));
block.addStatement(valInit);
idx++;
}
context.objectStack.push(block);
return data;
}

@Override
public Object visit(ASTReturn node, Object data) {
Context context = (Context) data;
Expand Down
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2012-2015 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/

package fr.insalyon.citi.golo.compiler.parser;

import java.util.List;
import java.util.ArrayList;
import static java.util.Collections.unmodifiableList;

public class ASTDestructuringAssignment extends GoloASTNode {

private ASTLetOrVar.Type type;
private List<String> names;
private boolean isVarargs = false;

public ASTDestructuringAssignment(int id) {
super(id);
}

public ASTDestructuringAssignment(GoloParser p, int id) {
super(p, id);
}

public ASTLetOrVar.Type getType() {
return type;
}

public void setType(ASTLetOrVar.Type type) {
this.type = type;
}

public List<String> getNames() {
return unmodifiableList(names);
}

public void setNames(List<String> names) {
this.names = new ArrayList<>();
this.names.addAll(names);
}

public void setVarargs(boolean b) {
this.isVarargs = b;
}

public boolean isVarargs() {
return this.isVarargs;
}

@Override
public String toString() {
return "ASTDestructuringAssignment{" +
"type=" + type +
", names=" + names +
", varargs=" + isVarargs +
"}";
}

@Override
public Object jjtAccept(GoloParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}
Expand Up @@ -243,6 +243,11 @@ public Object visit(ASTLetOrVar node, Object data) {
return data;
}

@Override
public Object visit(ASTDestructuringAssignment node, Object data) {
return data;
}

@Override
public Object visit(ASTContinue node, Object data) {
return data;
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/gololang/AbstractRange.java
Expand Up @@ -12,6 +12,7 @@
import java.util.AbstractCollection;
import java.util.Iterator;
import java.util.Arrays;
import java.util.LinkedList;

abstract class AbstractRange<T extends Comparable<T>> extends AbstractCollection<T> implements Range<T> {
private final T from;
Expand Down Expand Up @@ -130,4 +131,12 @@ public T head() {
public boolean isEmpty() {
return from.compareTo(to) >= 0;
}

public Tuple destruct() {
LinkedList<T> vals = new LinkedList<>();
for (T v : this) {
vals.add(v);
}
return Tuple.fromArray(vals.toArray());
}
}
9 changes: 9 additions & 0 deletions src/main/java/gololang/GoloStruct.java
Expand Up @@ -53,6 +53,15 @@ public Tuple members() {
*/
public abstract Tuple values();

/**
* Destructuration helper.
*
* @return a tuple with the current values.
*/
public Tuple destruct() {
return values();
}

/**
* Gets a member value by name.
*
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/gololang/LazyList.java
Expand Up @@ -232,6 +232,16 @@ public <T> T[] toArray(T[] a) {
return this.asList().toArray(a);
}


/**
* Destructuration helper.
*
* @return a tuple of head and tail
*/
public Tuple destruct() {
return new Tuple(head(), tail());
}

/**
* Returns the element at the specified position in this list.
* <p>
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/gololang/Tuple.java
Expand Up @@ -182,10 +182,22 @@ public Object head() {
*/
@Override
public Tuple tail() {
return this.subTuple(1);
}

/**
*
*/
public Tuple destruct() { return this; }

public Tuple subTuple(int start) {
return this.subTuple(start, data.length);
}

public Tuple subTuple(int start, int end) {
if (this.isEmpty()) {
// we can return this since a Tuple is immutable.
return this;
}
return fromArray(Arrays.copyOfRange(data, 1, data.length));
return fromArray(Arrays.copyOfRange(data, start, end));
}
}
49 changes: 48 additions & 1 deletion src/main/jjtree/Golo.jjt
Expand Up @@ -928,7 +928,9 @@ void Statement() #void:{}
|
Return()
|
LetOrVar()
LOOKAHEAD(3) DestructuringAssignment()
|
LOOKAHEAD(3) LetOrVar()
|
ConditionalBranching()
|
Expand Down Expand Up @@ -1331,6 +1333,51 @@ void Reference():{}
}
}

ASTDestructuringAssignment DestructuringAssignment():
{
List<String> names;
Token varargsToken = null;
}
{
<LET> names=DestructuredNames() (varargsToken="...")? "=" (BlankLine())? ExpressionStatement()
{
jjtThis.setType(ASTLetOrVar.Type.LET);
jjtThis.setNames(names);
jjtThis.setVarargs(varargsToken != null);
return jjtThis;
}
|
<VAR> names=DestructuredNames() (varargsToken="...")? "=" (BlankLine())? ExpressionStatement()
{
jjtThis.setType(ASTLetOrVar.Type.VAR);
jjtThis.setNames(names);
jjtThis.setVarargs(varargsToken != null);
return jjtThis;
}
}

List<String> DestructuredNames() #void:
{
List<String> names = new LinkedList<String>();
Token rootToken;
Token nextToken;
}
{
rootToken=<IDENTIFIER>
{
names.add(rootToken.image);
}
(
"," (BlankLine())? nextToken=<IDENTIFIER>
{
names.add(nextToken.image);
}
)+
{
return names;
}
}

ASTLetOrVar LetOrVar():
{
Token idToken;
Expand Down

0 comments on commit 2f1dc71

Please sign in to comment.