package synthesijer.scheduler;
import java.util.ArrayList;
import java.util.Hashtable;
import synthesijer.SynthesijerUtils;
import synthesijer.ast.Module;
import synthesijer.ast.Type;
import synthesijer.ast.type.ChannelType;
import synthesijer.ast.type.MultipleType;
import synthesijer.ast.type.TypeGen;
public class IRReader {
public final String fileName;
private final SExp sexp;
public final SchedulerInfo result;
public IRReader(String src){
this.fileName = src;
try{
sexp = SExp.load(src);
result = parseModule(sexp);
}catch(Exception e){
throw new RuntimeException(e);
}
}
private SchedulerInfo parseModule(SExp sexp) throws Exception{
SchedulerInfo info;
ArrayList<ChainingInfo> chainingVars = new ArrayList<>();
if(sexp.size() > 1 && sexp.get(0).equals("MODULE")){
Module m = new Module(sexp.get(1).toString(), new Hashtable<String, String>(), "", new ArrayList<String>());
info = new SchedulerInfo(sexp.get(1).toString(), m);
}else{
throw new IRReaderException("Illegal format");
}
for(int i = 2; i < sexp.size(); i++){
Object o = sexp.get(i);
if(o instanceof SExp && ((SExp)o).size() > 0){
SExp child = (SExp)o;
switch(child.get(0).toString()){
case "VARIABLES":
parseVariables(child, info, info.getModuleVarList(), chainingVars);
break;
case "BOARD":
parseBoard(child, info, chainingVars);
break;
default:
throw new IRReaderException("Illegal format: expected VARIABLES or BOARD, but " + o);
}
}else{
throw new IRReaderException("Illegal format: expected VARIABLES or BOARD, but " + o);
}
}
genChainingRelations(info, chainingVars);
return info;
}
private void genChainingRelations(SchedulerInfo info, ArrayList<ChainingInfo> chainingVars) throws Exception{
for(ChainingInfo chaining: chainingVars){
SExp list = chaining.expr;
for(int i = 0; i < list.size(); i++){
SExp e = (SExp)(list.get(i));
String ctx_name = e.get(0).toString();
int ctx_id = Integer.parseInt(e.get(1).toString());
SchedulerItem ctx = searchConsumingItem(info, ctx_name, ctx_id, chaining.o);
SchedulerItem pred = searchProducingItem(info, ctx_name, ctx_id, chaining.o);
//System.out.println(ctx.info());
//System.out.println(" <- " + pred.info());
chaining.o.setChaining(ctx, pred);
}
}
}
private SchedulerItem searchConsumingItem(SchedulerInfo info, String name, int id, Operand target){
SchedulerBoard board = null;
for(SchedulerBoard b: info.getBoardsList()){
if(b.getName().equals(name)){ board = b; break; }
}
if(board == null) return null;
SchedulerSlot slot = null;
for(SchedulerSlot s: board.getSlots()){
if(s.getStepId() == id){ slot = s; break; }
}
if(slot == null) return null;
for(SchedulerItem i: slot.getItems()){
Operand[] src = i.getSrcOperand();
for(Operand o: src){
if(o == target) return i;
}
}
return null;
}
private SchedulerItem searchProducingItem(SchedulerInfo info, String name, int id, Operand target){
SchedulerBoard board = null;
for(SchedulerBoard b: info.getBoardsList()){
if(b.getName().equals(name)){ board = b; break; }
}
if(board == null) return null;
SchedulerSlot slot = null;
for(SchedulerSlot s: board.getSlots()){
if(s.getStepId() == id){ slot = s; break; }
}
if(slot == null) return null;
for(SchedulerItem i: slot.getItems()){
Operand dest = i.getDestOperand();
if(dest == target) return i;
}
return null;
}
private void parseVariables(SExp sexp, SchedulerInfo info, ArrayList<Operand> table, ArrayList<ChainingInfo> chainingVars) throws Exception{
for(int i = 1; i < sexp.size(); i++){
Object o = sexp.get(i);
if(o instanceof SExp && ((SExp)o).size() > 0){
SExp child = (SExp)o;
switch(child.get(0).toString()){
case "VAR":
table.add(genVariableOperand(child, info, table, chainingVars));
break;
case "CONSTANT":
table.add(genConstantOperand(child));
break;
case "ARRAY-REF":
table.add(genArrayRefOperand(child));
break;
case "INSTANCE-REF":
table.add(genInstanceRefOperand(child));
break;
case "VAR-REF":
table.add(genVarRefOperand(child, table));
break;
default:
throw new IRReaderException("Illegal format: expected VAR or CONSTANT, but " + o);
}
}else{
throw new IRReaderException("Illegal format: expected VAR or CONSTANT, but " + o);
}
}
for(Operand o: table){
if(o instanceof VariableOperand){
VariableOperand v = (VariableOperand)o;
if(v.getInitSrc() != null && v.getInitSrc() instanceof TemporalOperand){ // local
Operand replaced = search(table, v.getInitSrc().getName());
v.setInitSrc(replaced);
}
if(v.getInitSrc() != null && v.getInitSrc() instanceof TemporalOperand){ // global
Operand replaced = search(info.getModuleVarList(), v.getInitSrc().getName());
v.setInitSrc(replaced);
}
}
}
}
private Operand search(ArrayList<Operand> table, String k){
for(Operand o: table){
if(o.getName().equals(k)) return o;
}
return new TemporalOperand(k);
}
private VariableOperand genVariableOperand(SExp node, SchedulerInfo info, ArrayList<Operand> table, ArrayList<ChainingInfo> chainingVars) throws Exception{
String name = node.get(2).toString();
Type type;
if(node.get(1) instanceof String){
type = TypeGen.get(node.get(1).toString());
}else if(node.get(1) instanceof SExp){
// too AD-HOC
SExp t = (SExp)(node.get(1));
if(t.get(0) instanceof String && t.get(0).toString().equals(MultipleType.KEY)){
ArrayList<Type> types = new ArrayList<Type>();
for(int i = 1; i < t.size(); i++){
types.add(TypeGen.get(t.get(i).toString()));
}
type = new MultipleType(types);
}else if(t.get(0) instanceof String && t.get(0).toString().equals(ChannelType.KEY)){
type = new ChannelType(TypeGen.get(t.get(1).toString()));
}else{
SynthesijerUtils.warn("unknown type: " + t);
SynthesijerUtils.warn("This type is handled as UNDEFINED");
type = TypeGen.get("UNDEFINED");
}
}else{
SynthesijerUtils.warn("unknown type: " + node.get(1));
SynthesijerUtils.warn("This type is handled as UNDEFINED");
type = TypeGen.get("UNDEFINED");
}
Operand initSrc = null;
boolean publicFlag = false;
boolean globalConstantFlag = false;
boolean methodParamFlag = false;
String origName = null;
String methodName = null;
boolean privateMethodFlag = false;
boolean volatileFlag = false;
boolean memberFlag = false;
boolean chainingFlag = false;
SExp chainingList = null;
for(int i = 3; i < node.size(); i = i + 2){
String k = node.get(i).toString();
Object v = node.get(i+1);
switch(k){
case ":public": publicFlag = Boolean.parseBoolean(v.toString()); break;
case ":global_constant": globalConstantFlag = Boolean.parseBoolean(v.toString()); break;
case ":method_param":methodParamFlag = Boolean.parseBoolean(v.toString()); break;
case ":original": origName = v.toString(); break;
case ":method": methodName = v.toString(); break;
case ":private_method": privateMethodFlag = Boolean.parseBoolean(v.toString()); break;
case ":volatile": volatileFlag = Boolean.parseBoolean(v.toString()); break;
case ":member": memberFlag = Boolean.parseBoolean(v.toString()); break;
case ":init":{
if(v instanceof SExp && ((SExp)v).size() > 0){
SExp child = ((SExp)v);
if(child.get(0).equals("REF")){
Operand target = search(table, child.get(2).toString());
initSrc = target;
}else{
throw new IRReaderException("expected REF object for the argument of :init" + node);
}
}else{
throw new IRReaderException("expected SExp object for the argument of :init" + node);
}
break;
}
case ":chaining":{
chainingFlag = true;
chainingList = (SExp)v;
}
break;
default:
SynthesijerUtils.warn("unknown keyword : " + k + ", the value " + v + " is skipped for " + name);
}
}
VariableOperand v = new VariableOperand(
name, type, initSrc, publicFlag, globalConstantFlag, methodParamFlag, origName, methodName, privateMethodFlag, volatileFlag, memberFlag);
if(chainingFlag){
chainingVars.add(new ChainingInfo(v, chainingList));
}
return v;
}
private ConstantOperand genConstantOperand(SExp node) throws Exception{
String name = node.get(2).toString();
Type type = TypeGen.get(node.get(1).toString());
String value = node.get(3).toString();
ConstantOperand c = new ConstantOperand(name, value, type);
return c;
}
private ArrayRefOperand genArrayRefOperand(SExp node) throws Exception{
String name = node.get(2).toString();
Type type = TypeGen.get(node.get(1).toString());
int depth = Integer.parseInt(parseArgument(node, ":depth").toString());
int words = Integer.parseInt(parseArgument(node, ":words").toString());
ArrayRefOperand o = new ArrayRefOperand(name, type, depth, words);
return o;
}
private InstanceRefOperand genInstanceRefOperand(SExp node) throws Exception{
String name = node.get(2).toString();
String className = node.get(1).toString();
Type type = TypeGen.get("DECLARED");
InstanceRefOperand o = new InstanceRefOperand(name, type, className);
return o;
}
private VariableRefOperand genVarRefOperand(SExp node, ArrayList<Operand> table) throws Exception{
String name = node.get(2).toString();
Type type = TypeGen.get(node.get(1).toString());
VariableOperand ref = null;
Operand ptr = null;
boolean memberFlag = false;
for(int i = 3; i < node.size(); i = i + 2){
String k = node.get(i).toString();
Object v = node.get(i+1);
switch(k){
case ":ref": ref = (VariableOperand)(search(table, v.toString())); break;
case ":ptr": ptr = search(table, v.toString()); break;
case ":member": memberFlag = Boolean.parseBoolean(v.toString()); break;
default:
SynthesijerUtils.warn("skip option:" + k);
}
}
VariableRefOperand o = new VariableRefOperand(name, type, ref, ptr, memberFlag);
return o;
}
private void parseBoard(SExp sexp, SchedulerInfo info, ArrayList<ChainingInfo> chainingVars) throws Exception{
String name = sexp.get(2).toString();
Type returnType;
if(sexp.get(1) instanceof String){
returnType = TypeGen.get(sexp.get(1).toString());
}else if(sexp.get(1) instanceof SExp){
// too AD-HOC
SExp t = (SExp)(sexp.get(1));
if(t.get(0) instanceof String && t.get(0).toString().equals(MultipleType.KEY)){
ArrayList<Type> types = new ArrayList<Type>();
for(int i = 1; i < t.size(); i++){
types.add(TypeGen.get(t.get(i).toString()));
}
returnType = new MultipleType(types);
}else if(t.get(0) instanceof String && t.get(0).toString().equals(ChannelType.KEY)){
returnType = new ChannelType(TypeGen.get(t.get(1).toString()));
}else{
SynthesijerUtils.warn("unknown type: " + t);
SynthesijerUtils.warn("This type is handled as UNDEFINED");
returnType = TypeGen.get("UNDEFINED");
}
}else{
SynthesijerUtils.warn("unknown type: " + sexp.get(1));
SynthesijerUtils.warn("This type is handled as UNDEFINED");
returnType = TypeGen.get("UNDEFINED");
}
boolean privateFlag = false;
boolean autoFlag = false;
boolean callStackFlag = false;
int callStackSize = -1;
boolean hasWaitWithMethod = false;
String waitMethodName = "";
int i = 3;
while(i < sexp.size()){
Object o = sexp.get(i);
if(o instanceof String){
String k = o.toString();
Object v = sexp.get(i+1);
switch(k){
case ":private": privateFlag = Boolean.parseBoolean(v.toString()); break;
case ":auto": autoFlag = Boolean.parseBoolean(v.toString()); break;
case ":call_stack_size":{
callStackFlag = true;
callStackSize = Integer.parseInt(v.toString());
}
break;
case ":dependent_board":{
hasWaitWithMethod = true;
waitMethodName = v.toString();
}
break;
default:
SynthesijerUtils.warn("unknown keyword : " + k + ", the value " + v + " is skipped");
}
i = i + 2;
}else{
i = i + 1;
}
}
SchedulerBoard board = new SchedulerBoard(name, returnType, privateFlag, autoFlag, callStackFlag, callStackSize, hasWaitWithMethod, waitMethodName);
for(i = 3; i < sexp.size(); i++){
Object o = sexp.get(i);
if(o instanceof SExp && ((SExp)o).size() > 0){
SExp child = (SExp)o;
switch(child.get(0).toString()){
case "VARIABLES":
parseVariables(child, info, board.getVarList(), chainingVars);
break;
case "SEQUENCER":
parseSequencer(child, info, board);
break;
default:
throw new IRReaderException("Illegal format: expected VARIABLES or SEQUENCER, but " + o);
}
}else{
throw new IRReaderException("Illegal format: expected VARIABLES or SEQUENCER, but " + o);
}
}
info.addBoard(board);
}
private void parseSequencer(SExp node, SchedulerInfo info, SchedulerBoard board) throws Exception{
for(int i = 2; i < node.size(); i++){
Object o = node.get(i);
if(o instanceof SExp && ((SExp)o).size() > 0){
SExp child = (SExp)o;
if(child.get(0).equals("SLOT")){
SchedulerSlot slot = parseSlot(child, info, board);
board.addSlot(slot);
}else{
throw new IRReaderException("Illegal format: expected SLOT, but " + o);
}
}else{
throw new IRReaderException("Illegal format: expected SExp object of SLOT, but " + o);
}
}
}
private SchedulerSlot parseSlot(SExp node, SchedulerInfo info, SchedulerBoard board) throws Exception{
int id = Integer.parseInt(node.get(1).toString());
SchedulerSlot slot = new SchedulerSlot(id);
for(int i = 2; i < node.size(); i++){
Object o = node.get(i);
if(o instanceof SExp && ((SExp)o).size() > 0){
SExp child = (SExp)o;
parseItem(child, info, board, slot);
}else{
throw new IRReaderException("Illegal format: expected SExp object of some items, but " + o);
}
}
return slot;
}
private Operand search(SchedulerInfo info, SchedulerBoard board, String k){
for(Operand o: board.getVarList()){
if(o.getName().equals(k)) return o;
}
for(Operand o: info.getModuleVarList()){
if(o.getName().equals(k)) return o;
}
return new TemporalOperand(k);
}
public void parseItem(SExp node, SchedulerInfo info, SchedulerBoard board, SchedulerSlot slot) throws Exception{
String opLabel = node.get(0).toString();
SchedulerItem item = null;
switch(opLabel){
case "METHOD_ENTRY":{
item = new MethodEntryItem(board, board.getName());
}
break;
case "CALL":{
// MethodInvokeItem
String name = parseArgument(node, ":name").toString();
SExp n = (SExp)(parseArgument(node, ":args"));
String[] args = new String[n.size()];
Operand[] src = parseSrcOperands(node, info, board);
for(int i = 0; i < args.length; i++) args[i] = n.get(i).toString();
MethodInvokeItem mii = new MethodInvokeItem(board, name, src, null, args);
boolean nowait = Boolean.parseBoolean(parseArgument(node, ":no_wait").toString());
mii.setNoWait(nowait);
item = mii;
}
break;
case "EXT_CALL":{
// MethodInvokeItem
String name = parseArgument(node, ":name").toString();
Operand obj = search(info, board, parseArgument(node, ":obj").toString());
SExp n = (SExp)(parseArgument(node, ":args"));
String[] args = new String[n.size()];
Operand[] src = parseSrcOperands(node, info, board);
for(int i = 0; i < args.length; i++) args[i] = n.get(i).toString();
item = new MethodInvokeItem(board, (VariableOperand)obj, name, src, null, args);
}
break;
case "FIELD_ACCESS":{
// FieldAccessItem
Operand obj = search(info, board, parseArgument(node, ":obj").toString());
String name = parseArgument(node, ":name").toString();
Operand[] src = parseSrcOperands(node, info, board);
item = new FieldAccessItem(board, (VariableOperand)obj, name, src, null);
}
break;
case "SELECT":{
Operand target = search(info, board, parseArgument(node, ":target").toString());
SExp args = (SExp)(parseArgument(node, ":patterns"));
Operand[] pat = new Operand[args.size()];
for(int i = 0; i < pat.length; i++){
pat[i] = search(info, board, args.get(i).toString());
}
item = new SelectItem(board, target, pat);
}
break;
case "FIFO_WRITE":
case "SET":{
// with destination
Operand dest = search(info, board, node.get(1).toString());
SExp expr = (SExp)(node.get(2));
Op op = Op.parseOp(expr.get(0).toString());
Operand[] src = parseSrcOperands(expr, info, board);
switch(op){
case CALL:{
String name = parseArgument(expr, ":name").toString();
SExp n = (SExp)(parseArgument(expr, ":args"));
String[] args = new String[n.size()];
for(int i = 0; i < args.length; i++) args[i] = n.get(i).toString();
MethodInvokeItem mii = new MethodInvokeItem(board, name, src, (VariableOperand)dest, args);
boolean nowait = Boolean.parseBoolean(parseArgument(expr, ":no_wait").toString());
mii.setNoWait(nowait);
item = mii;
}
break;
case EXT_CALL:{
String name = parseArgument(expr, ":name").toString();
Operand obj = search(info, board, parseArgument(expr, ":obj").toString());
SExp n = (SExp)(parseArgument(expr, ":args"));
String[] args = new String[n.size()];
for(int i = 0; i < args.length; i++) args[i] = n.get(i).toString();
item = new MethodInvokeItem(board, (VariableOperand)obj, name, src, (VariableOperand)dest, args);
}
break;
case FIELD_ACCESS:{
Operand obj = search(info, board, parseArgument(expr, ":obj").toString());
String name = parseArgument(expr, ":name").toString();
item = new FieldAccessItem(board, (VariableOperand)obj, name, src, (VariableOperand)dest);
}
break;
case CAST:{
// TypeCastItem
Type orig = TypeGen.get(parseArgument(expr, ":orig").toString());
Type target = TypeGen.get(parseArgument(expr, ":target").toString());
item = TypeCastItem.newCastItem(board, src[0], (VariableOperand)dest, orig, target);
}
break;
default:{
//System.out.println(dest.toSexp());
item = new SchedulerItem(board, op, src, (VariableOperand)dest);
}
}
}
break;
default:{
Op op = Op.parseOp(opLabel);
Operand[] src = parseSrcOperands(node, info, board);
item = new SchedulerItem(board, op, src, null);
}
}
if(item != null){
item.setBranchIds(parseBranchIds(node));
slot.addItem(item);
item.setSlot(slot);
}else{
SynthesijerUtils.warn("skipped:" + node);
}
}
private Operand[] parseSrcOperands(SExp node, SchedulerInfo info, SchedulerBoard board) throws Exception{
ArrayList<Operand> operands = new ArrayList<>();
int i = 1;
while(i < node.size()){
if(node.get(i).toString().startsWith(":")){
i = i + 2;
}else{
operands.add(search(info, board, node.get(i).toString()));
i = i + 1;
}
}
return operands.toArray(new Operand[]{});
}
private int[] parseBranchIds(SExp node) throws Exception{
int id = -1;
for(int i = 0; i < node.size(); i++){
if(node.get(i).toString().equals(":next") && node.get(i+1) instanceof SExp){
id = i+1;
break;
}
}
int[] d;
if(id > 0){
SExp n = (SExp)(node.get(id));
d = new int[n.size()];
for(int i = 0; i < d.length; i++){
d[i] = Integer.parseInt(n.get(i).toString());
}
}else{
d = new int[]{};
}
return d;
}
private Object parseArgument(SExp node, String k) throws Exception{
for(int i = 0; i < node.size(); i++){
if(node.get(i).toString().equals(k)){
return node.get(i+1);
}
}
return null;
}
private class ChainingInfo{
public final VariableOperand o;
public final SExp expr;
public ChainingInfo(VariableOperand o, SExp expr){
this.o = o;
this.expr = expr;
}
}
public static void main(String... args) throws Exception{
IRReader reader = new IRReader(args[0]);
if(args.length == 2) return;
System.out.println("VARIABLES:");
for(Operand v: reader.result.getModuleVarList()){
System.out.println(v.dump());
}
System.out.println("");
System.out.println("BOARDS");
for(SchedulerBoard b: reader.result.getBoardsList()){
System.out.println("BOARD:" + b.getName());
System.out.println("VARIABLES:");
for(Operand v: b.getVarList()){
System.out.println(v.dump());
}
System.out.println("SEQUENCER:");
b.dump(System.out);
}
}
}
class IRReaderException extends Exception{
public IRReaderException(String s){
super(s);
}
}