R lpa => cons +2 -2
@@ 43,9 43,9 @@ if(! ~ $#* 0)
usage
# Start LPA if it isn't already running
-lpafs
+lpa/fs
# Make /mnt/lpa available to sam and rio..
-plumb 'Local lpafs'
+plumb 'Local lpa/fs'
if(~ $printlist 1){
echo `{cd /mnt/lpa; ls | grep -v '^new$'}
M dat.h => dat.h +26 -6
@@ 34,6 34,8 @@ extern DataSpec dataspecs[DataMax]; /* memory.c */
typedef struct Symbol Symbol;
typedef struct Symtab Symtab;
+typedef struct Module Module;
+typedef struct Session Session;
struct Symbol
{
@@ 51,16 53,16 @@ struct Symtab
uvlong count;
Symbol **symbols;
+ Module *module;
};
-typedef struct Module Module;
struct Module
{
uvlong id;
char *name;
Symtab *symtab;
- Qid qsession;
+ Session *session;
Qid qmodule;
};
@@ 72,13 74,13 @@ struct ModuleList
Module **modules;
};
-typedef struct Session Session;
struct Session
{
uvlong id;
char *name;
int active; /* is the session alive? */
+ int debugtrace; /* slow evaluation with plumb of localtion */
ModuleList *modules;
@@ 132,6 134,7 @@ struct Token
{
int tag;
int nameclass;
+ int line;
union {
vlong num; /* TokNumber */
char *name; /* TokName: UTF-8 encoded name */
@@ 187,6 190,9 @@ struct Ast
int prim;
int optional; /* optional left arg */
+ int linestart;
+ int lineend;
+
Ast *funcname;
Ast *funcresult;
Ast *funcleftarg;
@@ 215,19 221,23 @@ enum Nameclass
struct ByteCode
{
+ Module *module;
+
uvlong count;
u8int *instrs;
};
enum Instr
{
- IPushConst,
+ IPushConst = 1,
IPushPrim,
ILookup,
IStrand,
INiladic,
IMonadic,
IDyadic,
+ ICall,
+ ITailCall,
IParse,
IReturn,
IAssign,
@@ 235,11 245,15 @@ enum Instr
IPop,
IDisplay,
IPushVar,
+ IFuncres,
+
+ ILine,
};
typedef struct ValueStack ValueStack;
struct ValueStack
{
+ int shy; /* is the top-most element shy? */
uvlong count;
void **values;
};
@@ 258,6 272,8 @@ struct LocalList
Local *list;
};
+typedef struct Function Function;
+
typedef struct CallFrame CallFrame;
struct CallFrame
{
@@ 265,6 281,11 @@ struct CallFrame
ByteCode *code;
uvlong offset;
+ /* For debugtrace */
+ int line;
+ int instr;
+ Function *func;
+
/* Old values of symbols before they were localised */
LocalList *locals;
};
@@ 284,7 305,6 @@ enum Valence
Variadic = 6,
};
-typedef struct Function Function;
struct Function
{
Ast *ast;
@@ 377,4 397,4 @@ struct ConstraintGraph
ConstraintVar *vs[128];
Constraint *cs[128];
-};>
\ No newline at end of file
+};
M eval.c => eval.c +193 -99
@@ 14,10 14,11 @@ eval(Session *s, Ast *a)
/* Evaluate some ast in module m in session s. */
Module *m = s->modules->modules[0]; /* TODO: this isn't nice */
ByteCode *code = codegen(s, m, a);
+ optimisebc(code, nil, m->symtab);
return evalbc(s, m, code);
}
-static void
+void
emitbyte(ByteCode *c, u8int i)
{
c->count += 1;
@@ 57,15 58,20 @@ emitlocal(ByteCode *c, Symtab *s, Ast *a, int assign)
}
static void
-codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
+codegensub(Session *s, ByteCode *c, Ast *a, int funcres, int *line)
{
uvlong i;
+ if(a->linestart != *line){
+ emitbyte(c, ILine);
+ emituvlong(c, a->linestart);
+ *line = a->linestart;
+ }
+
switch(a->tag){
case AstProg:
for(i = 0; i < a->childcount; i++){
- codegensub(s, m, c, a->children[i]);
- emitbyte(c, IPop);
+ codegensub(s, c, a->children[i], 0, line);
emitbyte(c, IDisplay);
}
break;
@@ 85,23 91,27 @@ codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
if(fn->ast->funcresult)
fn->hasresult = 1;
- fn->symbol = sym(m->symtab, a->funcname->name);
+ fn->symbol = sym(c->module->symtab, a->funcname->name);
fn->code = alloc(DataByteCode);
+ fn->code->module = c->module;
+ emitbyte(fn->code, ILine);
+ emituvlong(fn->code, a->linestart);
emitbyte(fn->code, IPushConst);
emitptr(fn->code, fn);
- emitlocal(fn->code, m->symtab, fn->ast->funcname, 1);
- emitlocal(fn->code, m->symtab, fn->ast->funcresult, 0);
- emitlocal(fn->code, m->symtab, fn->ast->funcleftarg, 1);
- emitlocal(fn->code, m->symtab, fn->ast->funcrightarg, 1);
+ emitlocal(fn->code, c->module->symtab, fn->ast->funcname, 1);
+ emitlocal(fn->code, c->module->symtab, fn->ast->funcresult, 0);
+ emitlocal(fn->code, c->module->symtab, fn->ast->funcleftarg, 1);
+ emitlocal(fn->code, c->module->symtab, fn->ast->funcrightarg, 1);
for(i = 0; i < fn->ast->funclocals->childcount; i++)
- emitlocal(fn->code, m->symtab, fn->ast->funclocals->children[i], 0);
+ emitlocal(fn->code, c->module->symtab, fn->ast->funclocals->children[i], 0);
for(i = 0; i < a->childcount; i++){
- codegensub(s, m, fn->code, a->children[i]);
+ codegensub(s, fn->code, a->children[i], 0, line);
emitbyte(fn->code, IPop);
}
if(fn->ast->funcresult)
- codegensub(s, m, fn->code, fn->ast->funcresult);
+ codegensub(s, fn->code, fn->ast->funcresult, 1, line);
emitbyte(fn->code, IReturn);
+ optimisebc(fn->code, fn->ast, c->module->symtab);
emitbyte(c, IPushConst);
emitptr(c, fn);
@@ 112,12 122,12 @@ codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
break;
case AstName:
emitbyte(c, ILookup);
- emituvlong(c, sym(m->symtab, a->name));
+ emituvlong(c, sym(c->module->symtab, a->name));
break;
case AstAssign:
- codegensub(s, m, c, a->right);
+ codegensub(s, c, a->right, 1, line);
emitbyte(c, IAssign);
- emituvlong(c, sym(m->symtab, a->left->name));
+ emituvlong(c, sym(c->module->symtab, a->left->name));
break;
case AstConst:
emitbyte(c, IPushConst);
@@ 126,24 136,33 @@ codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
case AstStrand:
/* right to left */
for(i = a->childcount; i > 0; i--)
- codegensub(s, m, c, a->children[i-1]);
+ codegensub(s, c, a->children[i-1], 1, line);
emitbyte(c, IStrand);
emituvlong(c, a->childcount);
break;
case AstNiladic:
- codegensub(s, m, c, a->func);
+ codegensub(s, c, a->func, 1, line);
emitbyte(c, INiladic);
+ emitbyte(c, IFuncres);
+ emituvlong(c, funcres);
+ emitbyte(c, ICall);
break;
case AstMonadic:
- codegensub(s, m, c, a->right);
- codegensub(s, m, c, a->func);
+ codegensub(s, c, a->right, 1, line);
+ codegensub(s, c, a->func, 1, line);
emitbyte(c, IMonadic);
+ emitbyte(c, IFuncres);
+ emituvlong(c, funcres);
+ emitbyte(c, ICall);
break;
case AstDyadic:
- codegensub(s, m, c, a->right);
- codegensub(s, m, c, a->left);
- codegensub(s, m, c, a->func);
+ codegensub(s, c, a->right, 1, line);
+ codegensub(s, c, a->left, 1, line);
+ codegensub(s, c, a->func, 1, line);
emitbyte(c, IDyadic);
+ emitbyte(c, IFuncres);
+ emituvlong(c, funcres);
+ emitbyte(c, ICall);
break;
case AstPrim:
emitbyte(c, IPushPrim);
@@ 152,19 171,30 @@ codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
case AstLater:
emitbyte(c, IParse);
emitptr(c, a->tokens);
+ emituvlong(c, funcres);
break;
default:
error(EInternal, "Don't know how to do codegen for ast type %d", a->tag);
break;
}
+ if(a->lineend != *line){
+ assert(a->lineend >= a->linestart);
+ assert(*line >= a->linestart);
+ emitbyte(c, ILine);
+ emituvlong(c, a->lineend);
+ *line = a->lineend;
+ }
+
}
static ByteCode *
codegen(Session *s, Module *m, Ast *a)
{
ByteCode *c = alloc(DataByteCode);
- codegensub(s, m, c, a);
+ c->module = m;
+ int line = 0;
+ codegensub(s, c, a, 0, &line);
return c;
}
@@ 174,6 204,7 @@ pushval(ValueStack *s, void *v)
s->count++;
s->values = allocextra(s, s->count * sizeof(v));
s->values[s->count-1] = v;
+ s->shy = 0;
}
static void *
@@ 182,6 213,7 @@ popval(ValueStack *s)
if(s->count == 0)
error(EInternal, "popval on empty value stack");
s->count--; /* no realloc */
+ s->shy = 0;
return s->values[s->count];
}
@@ 194,30 226,49 @@ peekval(ValueStack *s)
}
static void
-pushcall(CallStack *s, ByteCode *newcode, ByteCode **c, uvlong *o)
+pushcall(CallStack *s, ByteCode *newcode, ByteCode **c, uvlong *o, int *line, int *instr, Function **func, LocalList *locals)
{
s->count++;
s->frames = allocextra(s, s->count * sizeof(CallFrame));
s->frames[s->count-1].code = *c;
s->frames[s->count-1].offset = *o;
- s->frames[s->count-1].locals = alloc(DataLocalList);
+ s->frames[s->count-1].line = *line;
+ s->frames[s->count-1].instr = *instr;
+ s->frames[s->count-1].func = *func;
+ s->frames[s->count-1].locals = locals ? locals : alloc(DataLocalList);
*c = newcode;
*o = 0;
+ *line = 0;
+ *instr = 0;
+ *func = nil;
}
static void
-popcall(CallStack *s, Symtab *t, ByteCode **c, uvlong *o)
+popcall(Session *session, CallStack *s, Symtab *t, ByteCode **c, uvlong *o, int *line, int *instr, Function **func, LocalList **localsp)
{
if(s->count == 0)
error(EInternal, "popcall on empty call stack");
s->count--; /* no realloc */
+
+ if(session->debugtrace && *func){
+ char *name = funcname(*func);
+ plumbedit(*func, name, session, 0, -1);
+ plumbedit((*func)->code, name, session, 0, -1);
+ }
+
*c = s->frames[s->count].code;
*o = s->frames[s->count].offset;
+ *line = s->frames[s->count].line;
+ *instr = s->frames[s->count].instr;
+ *func = s->frames[s->count].func;
LocalList *locals = s->frames[s->count].locals;
- for(uvlong i = 0; i < locals->count; i++)
- symset(t, locals->list[i].id, locals->list[i].value);
+ if(localsp)
+ *localsp = locals; /* tail call */
+ else
+ for(uvlong i = 0; i < locals->count; i++)
+ symset(t, locals->list[i].id, locals->list[i].value);
}
static void
@@ 233,19 284,6 @@ pushlocal(CallStack *c, Symtab *s, uvlong id)
symset(s, id, nil);
}
-static int
-nextinstr(CallStack *calls, ByteCode *c, uvlong o)
-{
- if(o < c->count && c->instrs[o] != IReturn)
- return c->instrs[o];
- if(calls->count == 0)
- return -1;
- else{
- CallFrame f = calls->frames[calls->count-1];
- return f.code->instrs[f.offset];
- }
-}
-
static void
checkarray(void *val)
{
@@ 264,15 302,34 @@ evalbc(Session *s, Module *m, ByteCode *c)
Function *func;
void *r;
Array *x, *y, *z;
+ Array *(*primfn)(int, Array *, Array *);
+ LocalList *locals;
+
+ Function *currentfunc = nil;
+ int currentline = 0;
+ int currentinstr = 0;
values = alloc(DataValueStack);
calls = alloc(DataCallStack);
+ func = nil;
+ primfn = nil;
+ x = y = nil;
+ locals = nil;
+
o = 0;
while(o < c->count){
int instr = c->instrs[o];
o++;
+ currentinstr++;
+ if(s->debugtrace && currentfunc){
+ char *name = funcname(currentfunc);
+ plumbedit(currentfunc, name, s, 0, currentline);
+ plumbedit(currentfunc->code, name, s, 0, currentinstr);
+ sleep(1000);
+ }
+
switch(instr){
case IPushConst:
o += getuvlong(c->instrs+o, &v);
@@ 313,51 370,21 @@ evalbc(Session *s, Module *m, ByteCode *c)
break;
case INiladic:
func = popval(values);
- if(func->valence != Niladic){
- int next = nextinstr(calls, c, o);
- if(next == IAssign || IPop){
- pushval(values, func);
- break;
- }else
- error(ESyntax, "Function %s is not niladic", funcname(func));
- }
+ primfn = primnilad;
+ x = nil;
+ y = nil;
- if(func->code){
- if(!func->hasresult){
- if(nextinstr(calls, c, o) == IPop)
- pushval(values, nil); /* fake result */
- else
- error(ESyntax, "Function %s does not produce a result", funcname(func));
- }
- pushcall(calls, func->code, &c, &o);
- }else{
- z = primnilad(func->prim);
- pushval(values, z);
- }
+ if(!(func->valence == Niladic))
+ error(ESyntax, "Function %s is not niladic", funcname(func));
break;
case IMonadic:
- /* FIXME: more duplicated code with INiladic and IDyadic than i would like */
func = popval(values);
y = popval(values);
if(!(func->valence & Monadic))
error(ESyntax, "Function %s is not monadic", funcname(func));
checkarray(y);
-
- if(func->code){
- if(!func->hasresult){
- if(nextinstr(calls, c, o) == IPop)
- pushval(values, nil); /* fake result */
- else
- error(ESyntax, "Function %s does not produce a result", funcname(func));
- }
- pushval(values, y);
- if(func->valence & Dyadic) /* ambivalent function */
- pushval(values, nil);
- pushcall(calls, func->code, &c, &o);
- }else{
- z = primmonad(func->prim, y);
- pushval(values, z);
- }
+ primfn = primmonad;
+ x = nil;
break;
case IDyadic:
func = popval(values);
@@ 367,46 394,54 @@ evalbc(Session *s, Module *m, ByteCode *c)
error(ESyntax, "Function %s is not dyadic", funcname(func));
checkarray(x);
checkarray(y);
-
+ primfn = primdyad;
+ break;
+ case ITailCall:
+ popcall(s, calls, m->symtab, &c, &o, ¤tline, ¤tinstr, ¤tfunc, &locals);
+ /* fall through */
+ case ICall:
+ /* In all valid code, this comes after a INiladic, IMonadic or IDyadic and a
+ * IFuncres which means the call
+ * has been verified, and func is a pointer to the function to call.
+ * For primitives, x and y are setup.
+ */
if(func->code){
- if(!func->hasresult){
- if(nextinstr(calls, c, o) == IPop)
- pushval(values, nil); /* fake result */
- else
- error(ESyntax, "Function %s does not produce a result", funcname(func));
- }
- pushval(values, y);
- pushval(values, x);
- pushcall(calls, func->code, &c, &o);
+ pushcall(calls, func->code, &c, &o, ¤tline, ¤tinstr, ¤tfunc, locals);
+ currentfunc = func;
}else{
- z = primdyad(func->prim, x, y);
+ z = primfn(func->prim, x, y);
pushval(values, z);
}
+ locals = nil;
break;
case IParse:
/* parse at runtime and emit code */
o += getuvlong(c->instrs+o, &v);
{
TokenList *t = (TokenList *)v;
+ o += getuvlong(c->instrs+o, &v);
Ast *a = parse(t, m->symtab);
newcode = alloc(DataByteCode);
- codegensub(s, m, newcode, a);
+ newcode->module = c->module;
+ int line = 0;
+ codegensub(s, newcode, a, v, &line);
emitbyte(newcode, IReturn);
- pushcall(calls, newcode, &c, &o);
+ optimisebc(newcode, nil, nil);
+ pushcall(calls, newcode, &c, &o, ¤tline, ¤tinstr, ¤tfunc, nil);
+ currentfunc = nil;
}
break;
case IReturn:
- popcall(calls, m->symtab, &c, &o);
+ values->shy = 0;
+ popcall(s, calls, m->symtab, &c, &o, ¤tline, ¤tinstr, ¤tfunc, nil);
break;
case IAssign:
o += getuvlong(c->instrs+o, &v);
{
void *val = popval(values);
symset(m->symtab, v, val);
-
- if(nextinstr(calls, c, o) == IPop)
- val = nil;
pushval(values, val);
+ values->shy = 1;
}
break;
case ILocal:
@@ 414,17 449,41 @@ evalbc(Session *s, Module *m, ByteCode *c)
pushlocal(calls, m->symtab, v);
break;
case IPop:
- r = popval(values);
- if(nextinstr(calls, c, o) == IDisplay && r != nil)
- appendlog(s, printval(r));
+ popval(values);
break;
case IDisplay:
- /* nothing to do, IPop checks for it */
+ {
+ int shy = values->shy;
+ r = popval(values);
+ if(r != nil && !shy){
+ appendlog(s, printval(r));
+ appendlog(s, "\n");
+ }
+ }
break;
case IPushVar:
o += getuvlong(c->instrs+o, &v);
pushval(values, allocvar(symname(m->symtab, v)));
break;
+ case IFuncres:
+ o += getuvlong(c->instrs+o, &v);
+ if(func->code){
+ if(!func->hasresult){
+ if(v)
+ error(ESyntax, "Function %s does not produce a result", funcname(func));
+ pushval(values, nil); /* fake result */
+ }
+ if(func->valence & Dyadic){
+ pushval(values, y);
+ pushval(values, x);
+ }else if(func->valence & Monadic)
+ pushval(values, y);
+ }
+ break;
+ case ILine:
+ o += getuvlong(c->instrs+o, &v);
+ currentline = v;
+ break;
default:
error(EInternal, "unknown instruction in evalbc: %d", instr);
}
@@ 440,3 499,38 @@ evalbc(Session *s, Module *m, ByteCode *c)
r = popval(values);
return r;
}
+
+int
+instrsize(u8int instr)
+{
+ int size = 1;
+
+ switch(instr){
+ case IParse:
+ size += 2 * sizeof(uvlong);
+ break;
+ case IPushConst:
+ case IPushPrim:
+ case ILookup:
+ case IStrand:
+ case IAssign:
+ case ILocal:
+ case IPushVar:
+ case IFuncres:
+ case ILine:
+ size += sizeof(uvlong);
+ break;
+ case INiladic:
+ case IMonadic:
+ case IDyadic:
+ case ICall:
+ case ITailCall:
+ case IReturn:
+ case IPop:
+ case IDisplay:
+ break;
+ default:
+ error(EInternal, "unknown instruction in instrsize: %d", instr);
+ }
+ return size;
+}<
\ No newline at end of file
M fns.h => fns.h +12 -6
@@ 36,10 36,11 @@ _Noreturn void error(int, char *, ...);
/* eval.c */
void *eval(Session *s, Ast *);
+void emitbyte(ByteCode *, u8int);
+int instrsize(u8int);
/* fs.c */
Qid freshobjqid(void);
-void startfs(char *, char *);
/* memory.c */
void *alloc(int);
@@ 54,17 55,20 @@ Enumeration *enummodules(Session *s);
/* parse.c */
Ast *parse(TokenList *, Symtab *);
+/* optimise.c */
+void optimisebc(ByteCode *, Ast *, Symtab *);
+
/* prim.c */
char *primsymb(int);
int primclass(int);
int primvalence(int);
int primid(char *);
-Array *primnilad(int);
-Array *primmonad(int, Array *);
+Array *primnilad(int, Array *, Array *);
+Array *primmonad(int, Array *, Array *);
Array *primdyad(int, Array *, Array *);
/* scan.c */
-TokenList *scan(char *);
+TokenList *scan(char *, int);
char *printtok(Token);
/* session.c */
@@ 74,7 78,7 @@ Enumeration *enumsessions(void);
void appendlog(Session *s, char *data);
/* symtab.c */
-Symtab *allocsymtab(void);
+Symtab *allocsymtab(Module *);
uvlong sym(Symtab *, char *);
char *symname(Symtab *, uvlong);
void *symval(Symtab *, uvlong);
@@ 90,9 94,11 @@ void systemcmd(Session *, char *, int);
Enumeration *allocenum(uvlong);
void trim(char *);
void debugast(Ast *, int);
-void debugbc(ByteCode *);
+char *printbc(ByteCode *);
int getuvlong(u8int *, uvlong *);
char *funcname(Function *);
+void plumbedit(void *, char *, Session *, int, int);
+void plumbinfo(Session *, char *);
/* value.c */
char *printval(void *);
M fs.c => fs.c +92 -5
@@ 30,7 30,8 @@ enum {
Qmodules,
Qmodule,
Qthreads,
- Qlpaobj
+ Qlpaobj,
+ Qbytecode,
};
enum {
@@ 85,6 86,7 @@ mkqid(int type, uvlong id)
case Qcons:
case Qlog:
case Qlpaobj:
+ case Qbytecode:
qid.type = QTFILE;
break;
}
@@ 261,6 263,27 @@ sessionctl(Req *r)
}
static char *
+bytecode(Req *r)
+{
+ Aux *aux = r->fid->aux;
+ Symbol *symb = aux->symbol;
+
+ /* Pretty print the value and readstr() it. */
+ if(aux->cachestr == nil){
+ if(getalloctag(symb->value) != DataFunction)
+ return Eexist;
+ void *val = ((Function *)symb->value)->code;
+ aux->cachestr = printval(val);
+ }
+ readstr(r, aux->cachestr);
+ if(r->ofcall.count == 0){
+ free(aux->cachestr);
+ aux->cachestr = nil;
+ }
+ return nil;
+}
+
+static char *
symbolrw(Req *r)
{
Aux *aux = r->fid->aux;
@@ 277,8 300,11 @@ symbolrw(Req *r)
aux->cachestr = nil;
}
}else{ /* Twrite */
- if(trap(EAny))
- return errmsg();
+ if(trap(EAny)){
+ char *msg = errmsg();
+ plumbinfo(session, msg);
+ return msg;
+ }
char *buf = requeststr(r);
void *v = parseval(session, buf);
@@ 373,7 399,7 @@ fswalk1(Fid *fid, char *name, Qid *qid)
break;
case Qmodule:
if(strcmp(name, "..") == 0)
- *qid = m->qsession;
+ *qid = m->session->qsession;
else{
int found = 0;
e = enumsymbols(m->symtab, 1);
@@ 384,6 410,16 @@ fswalk1(Fid *fid, char *name, Qid *qid)
aux->symbol = symb;
found = 1;
}
+
+ if(symb->value != nil && getalloctag(symb->value) == DataFunction){
+ char *bcname = smprint("%s.bc", symb->name);
+ if(strcmp(name, bcname) == 0){
+ *qid = mkqid(Qbytecode, QID_PATH(symb->qsymbol));
+ aux->symbol = symb;
+ found = 1;
+ }
+ free(bcname);
+ }
}
if(!found)
err = Eexist;
@@ 438,7 474,6 @@ fsopen(Req *r)
s->qmodules = mkqid(Qmodules, s->id);
s->qthreads = mkqid(Qthreads, s->id);
- m->qsession = s->qsession;
m->qmodule = mkqid(Qmodule, m->id);
}
@@ 486,6 521,19 @@ fsstat(Req *r)
mkfilestat(&r->d, symb->name, symb->qsymbol, 0444);
r->d.length = strlen(printval(symb->value));
break;
+ case Qbytecode:
+ {
+ void *val = symb->value;
+ if(val == nil || getalloctag(val) != DataFunction){
+ err = Eexist;
+ break;
+ }
+
+ char *name = smprint("%s.bc", symb->name);
+ mkfilestat(&r->d, name, mkqid(Qbytecode, QID_PATH(symb->qsymbol)), 0444);
+ free(name);
+ }
+ break;
default:
err = Enotyet;
}
@@ 530,6 578,9 @@ fsread(Req *r)
case Qlpaobj:
err = symbolrw(r);
break;
+ case Qbytecode:
+ err = bytecode(r);
+ break;
default:
err = Enotyet;
break;
@@ 641,3 692,39 @@ startfs(char *name, char *mtpt)
threadpostmountsrv(&fs, name, mtpt, MREPL);
}
+
+void
+usage(void)
+{
+ fprint(2, "usage: lpa/fs [-D] [-n name] [-m mtpt] \n");
+ exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ char *name = "lpa";
+ char *mtpt = "/mnt/lpa";
+
+ ARGBEGIN{
+ case 'm':
+ mtpt = EARGF(usage());
+ break;
+ case 'n':
+ name = EARGF(usage());
+ break;
+ case 'D':
+ chatty9p++;
+ break;
+ default:
+ usage();
+ }ARGEND
+ if(argc != 0)
+ usage();
+
+ initarrays();
+ initsessions();
+
+ startfs(name, mtpt);
+ exits(nil);
+}
A ide.c => ide.c +965 -0
@@ 0,0 1,965 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <frame.h>
+#include <plumb.h>
+
+enum {
+ Stacksize = 8*1024,
+};
+
+enum {
+ MenuResize,
+ MenuMaximize,
+ MenuHide,
+ MenuClose,
+ MenuEdit,
+ MenuMax,
+};
+
+enum {
+ Wfunction,
+ Warray,
+ Wbytecode,
+ Wundefined,
+ Winfo,
+ Wsession,
+};
+
+enum {
+ Border = 2,
+ Padding = 2,
+ Scrollbar = 12,
+};
+
+Mousectl *mousectl;
+Keyboardctl *keyboardctl;
+char *typestrs[] = {
+ [Wfunction] = "function",
+ [Warray] = "array",
+ [Wbytecode] = "bytecode",
+ [Wundefined] = "undefined",
+ [Winfo] = "info",
+ [Wsession] = "session",
+};
+char *sessionid;
+Channel *sessionchan;
+Channel *editplumbchan;
+Channel *infoplumbchan;
+Image *background;
+
+typedef struct Window Window;
+struct Window
+{
+ Rectangle rect;
+ Frame frame;
+ Image *cols[NCOL];
+ int type;
+ Rune *title;
+ Rune *text;
+ Rune *extra;
+ char *path;
+ int hidden;
+ int needsrect;
+
+ int p0;
+ int p1;
+ Window *next;
+
+ int nlines;
+ int firstline;
+ int firstchar;
+};
+Window *windows;
+Window *sessionwin;
+Window *infowin;
+Window *focusedwin;
+
+int nwindows;
+Window **windowarray;
+
+int
+windowcmp(void *a, void *b)
+{
+ Window **wa = a;
+ Window **wb = b;
+
+ int r = (*wb)->type - (*wa)->type;
+ if(r == 0)
+ r = runestrcmp((*wa)->title, (*wb)->title);
+ return r;
+}
+
+Window *
+addwindow(char *name, int type, Rectangle rect)
+{
+ Rune *title;
+ Window *w = mallocz(sizeof(Window), 1);
+ if(w == nil)
+ sysfatal("malloc: %r");
+ w->type = type;
+ if(type == Wsession || type == Winfo)
+ title = runesmprint("%s %s", typestrs[type], name);
+ else
+ title = runesmprint("%s [%s]", name, typestrs[type]);
+ w->title = title;
+
+ switch(type){
+ case Wfunction:
+ w->cols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
+ w->cols[HIGH] = allocimagemix(display, DPalegreygreen, DPalegreygreen);
+ w->cols[BORD] = allocimagemix(display, DPurpleblue, DPurpleblue);
+ break;
+ case Warray:
+ w->cols[BACK] = allocimagemix(display, DPalegreen, DWhite);
+ w->cols[HIGH] = allocimagemix(display, DMedgreen, DMedgreen);
+ w->cols[BORD] = allocimagemix(display, DDarkgreen, DDarkgreen);
+ break;
+ case Wbytecode:
+ w->cols[BACK] = allocimagemix(display, 0xFFAAAAFF, DWhite);
+ w->cols[HIGH] = allocimagemix(display, 0xFFAAAAFF, 0xFFAAAAFF);
+ w->cols[BORD] = allocimagemix(display, 0xBB5D5DFF, 0xBB5D5DFF);
+ break;
+ case Wundefined:
+ w->cols[BACK] = allocimagemix(display, 0xEEEEEEFF, 0xEEEEEEFF);
+ w->cols[HIGH] = allocimagemix(display, 0xCCCCCCFF, 0xCCCCCCFF);
+ w->cols[BORD] = allocimagemix(display, 0x888888FF, 0x888888FF);
+ break;
+ case Winfo:
+ w->cols[BACK] = allocimagemix(display, 0xEEEEEEFF, 0xEEEEEEFF);
+ w->cols[HIGH] = allocimagemix(display, 0xCCCCCCFF, 0xCCCCCCFF);
+ w->cols[BORD] = allocimagemix(display, 0x888888FF, 0x888888FF);
+ break;
+ case Wsession:
+ w->cols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
+ w->cols[HIGH] = allocimagemix(display, DDarkyellow, DDarkyellow);
+ w->cols[BORD] = allocimagemix(display, DYellowgreen, DYellowgreen);
+ break;
+ }
+ w->cols[TEXT] = display->black;
+ w->cols[HTEXT] = display->black;
+ w->rect = rect;
+
+ if(windows == nil)
+ windows = w;
+ else{
+ Window *tmp = windows;
+ while(tmp->next)
+ tmp = tmp->next;
+ tmp->next = w;
+ }
+
+ nwindows++;
+ windowarray = realloc(windowarray, sizeof(*windowarray) * nwindows);
+ if(windowarray == nil)
+ sysfatal("realloc: %r");
+ windowarray[nwindows-1] = w;
+ qsort(windowarray, nwindows, sizeof(*windowarray), windowcmp);
+
+ return w;
+}
+
+void
+drawwin(Window *w)
+{
+ if(w->hidden)
+ return;
+
+ Rectangle r = w->rect;
+ int fontheight = display->defaultfont->height;
+
+ Image *bordercol;
+ if(w == focusedwin)
+ bordercol = w->cols[TEXT];
+ else
+ bordercol = w->cols[BORD];
+
+ draw(screen, r, w->cols[BACK], nil, ZP);
+ border(screen, r, Border, bordercol, ZP);
+ border(screen, Rect(r.min.x, r.min.y, r.max.x, r.min.y+fontheight+(Border*2)), Border, bordercol, ZP);
+ r = insetrect(r, Border);
+
+ Rectangle titlerect = r;
+ titlerect.max.y = titlerect.min.y+fontheight;
+ draw(screen, titlerect, w->cols[HIGH], nil, ZP);
+
+ r = insetrect(r, Padding);
+ titlerect = insetrect(titlerect, Padding);
+ _string(screen, r.min, w->cols[HTEXT], ZP, display->defaultfont, nil, w->title, runestrlen(w->title), titlerect, nil, ZP, SoverD);
+
+ r = Rect(r.min.x, r.min.y+fontheight+Border, r.max.x, r.max.y);
+
+ Rectangle scrollrect = insetrect(r, -Padding);
+ scrollrect.max.x = scrollrect.min.x + Scrollbar;
+ r.min.x += Scrollbar;
+
+ frclear(&w->frame, 0);
+ frinit(&w->frame, r, display->defaultfont, screen, w->cols);
+ long offset = w->firstchar;
+
+ Rune *strs[2] = {w->text, w->extra};
+ for(int n = 0; n < nelem(strs); n++){
+ if(strs[n] == nil)
+ continue;
+
+ long len = runestrlen(strs[n]);
+ if(len <= offset){
+ offset -= len;
+ continue;
+ }
+
+ len -= offset;
+ frinsert(&w->frame, strs[n]+offset, strs[n]+offset+len, w->frame.nchars);
+ offset = 0;
+ }
+ if(w->p0 != -1){
+ int p0 = w->p0 - w->firstchar;
+ int p1 = w->p1 - w->firstchar;
+ if(p0 >= 0 && p1 <= w->frame.nchars)
+ frdrawsel(&w->frame, frptofchar(&w->frame, p0), p0, p1, 1);
+ }
+
+ /* draw the scrollbar */
+ draw(screen, scrollrect, bordercol, nil, ZP);
+ scrollrect.max.x--;
+
+ if(w->nlines != 0){
+ int height = Dy(scrollrect);
+ scrollrect.min.y += (height * w->firstline)/w->nlines;
+
+ int hidden = w->nlines - (w->frame.maxlines+w->firstline);
+ if(hidden < 0)
+ hidden = 0;
+ scrollrect.max.y -= (height * hidden)/w->nlines;
+
+ if(scrollrect.min.y >= scrollrect.max.y)
+ scrollrect.min.y -= Border;
+ }
+ draw(screen, scrollrect, w->cols[BACK], nil, ZP);
+}
+
+void
+redraw(void)
+{
+ if(background == nil)
+ background = allocimagemix(display, 0x00807FFF, 0x00807FFF);
+ draw(screen, screen->r, background, nil, ZP);
+ for(Window *w = windows; w != nil; w = w->next)
+ drawwin(w);
+ flushimage(display, 1);
+}
+
+int
+movept(int oldstart, int oldend, int newstart, int newend, int n)
+{
+ int oldwidth = oldend-oldstart;
+ int newwidth = newend-newstart;
+
+ return ((newwidth*(n-oldstart))/oldwidth)+newstart;
+}
+
+void
+eresize(int new)
+{
+ Rectangle oldr, newr;
+ oldr = screen->r;
+ if(new && getwindow(display, Refnone) < 0)
+ sysfatal("getwindow: %r");
+ newr = screen->r;
+ for(Window *w = windows; w != nil; w = w->next){
+ w->rect.min.x = movept(oldr.min.x, oldr.max.x, newr.min.x, newr.max.x, w->rect.min.x);
+ w->rect.max.x = movept(oldr.min.x, oldr.max.x, newr.min.x, newr.max.x, w->rect.max.x);
+ w->rect.min.y = movept(oldr.min.y, oldr.max.y, newr.min.y, newr.max.y, w->rect.min.y);
+ w->rect.max.y = movept(oldr.min.y, oldr.max.y, newr.min.y, newr.max.y, w->rect.max.y);
+ }
+ redraw();
+}
+
+void
+resizewin(Window *w)
+{
+ Rectangle r = getrect(3, mousectl);
+ rectclip(&r, screen->r);
+ if(Dy(r) > 20 && Dx(r) > 20){ /* arbitrary limit */
+ w->rect = r;
+ w->hidden = 0;
+ w->needsrect = 0;
+ }else{
+ w->hidden = 1;
+ w->needsrect = 1;
+ }
+}
+
+void
+focuswin(Window *w)
+{
+ if(w)
+ focusedwin = w;
+ else{
+ focusedwin = nil;
+ goto end;
+ }
+
+ if(w->needsrect){
+ resizewin(w);
+ if(w->needsrect)
+ goto end;
+ }
+ w->hidden = 0;
+
+ Window *tmp;
+ for(tmp = windows; tmp != nil; tmp = tmp->next){
+ if(tmp->next == w){
+ tmp->next = w->next;
+ w->next = nil;
+ break;
+ }
+ }
+ if(w == windows){
+ if(windows->next == nil)
+ goto end;
+
+ windows = windows->next;
+ w->next = nil;
+ }
+
+ tmp = windows;
+ while(tmp->next)
+ tmp = tmp->next;
+ tmp->next = w;
+end:
+ redraw();
+}
+
+void
+removewindow(Window *w)
+{
+ if(w->type == Wsession || w->type == Winfo)
+ return;
+
+ /* TODO: cleanup stuff */
+ if(w == windows)
+ windows = windows->next;
+
+ for(Window *t = windows; t != nil && t->next != nil; t = t->next){
+ if(t->next == w)
+ t->next = w->next;
+ }
+
+ for(int i = 0; i < nwindows; i++){
+ if(windowarray[i] != w)
+ continue;
+ nwindows--;
+ memmove(&windowarray[i], &windowarray[i+1], sizeof(*windowarray) * (nwindows - i));
+ break;
+ }
+}
+
+Window *
+findwindow(char *path, int type, char *name)
+{
+ for(Window *w = windows; w != nil; w = w->next){
+ if(w->path && strcmp(w->path, path) == 0){
+ if(w->type != type){
+ Window *old = w;
+ w = addwindow(name, type, old->rect);
+ w->path = old->path;
+ w->hidden = old->hidden;
+ w->needsrect = old->needsrect;
+
+ if(focusedwin == old)
+ focusedwin = w;
+
+ removewindow(old);
+ }
+ return w;
+ }
+ }
+ return nil;
+}
+
+void
+countlines(Window *w)
+{
+ int offset = 0;
+ w->nlines = 0;
+ w->firstchar = 0;
+
+ Rune *strs[2] = {w->text, w->extra};
+ for(int n = 0; n < nelem(strs); n++){
+ for(Rune *r = strs[n]; r && *r; r++){
+ offset++;
+ if(*r == '\n'){
+ w->nlines++;
+ if(w->nlines == w->firstline)
+ w->firstchar = offset;
+ }
+ }
+ }
+ redraw();
+}
+
+void appendtext(Window *, Rune *);
+
+
+void
+fillwindow(Window *w)
+{
+ int fd = open(w->path, OREAD);
+ if(fd < 0){
+ Rune *msg = runesmprint("open: %r\n");
+ appendtext(infowin, msg);
+ return;
+ }
+
+ char *buf = mallocz(16*1024, 1);
+ if(read(fd, buf, 16*1024) < 0)
+ sysfatal("read: %r");
+ if(w->text)
+ free(w->text);
+ w->text = runesmprint("%s", buf);
+ free(buf);
+
+ countlines(w);
+}
+
+void scroll(Window *, int);
+
+void
+scrollto(Window *w, int line)
+{
+ if(line < w->firstline){
+ w->firstline = line;
+ countlines(w);
+ return;
+ }
+
+ int overflow = (line - w->firstline) - w->frame.maxlines;
+ if(overflow >= 0)
+ scroll(w, overflow+1);
+}
+
+void
+appendtext(Window *w, Rune *text)
+{
+ if(w->text){
+ Rune *tmp = runesmprint("%S%S", w->text, text);
+ free(w->text);
+ free(text);
+ w->text = tmp;
+ }else
+ w->text = text;
+ w->p0 = w->p1 = -1;
+ countlines(w);
+ scrollto(w, w->nlines);
+}
+
+void
+inputwin(Window *w, Rune k)
+{
+ if(w != sessionwin)
+ return;
+
+ if(k == '\n'){
+ char buf[1024];
+ sprint(buf, "/mnt/lpa/%s/cons", sessionid);
+
+ int fd = open(buf, OWRITE);
+ if(fd < 0)
+ sysfatal("open: %r");
+ fprint(fd, "%S\n", w->extra ? w->extra : L"");
+ close(fd);
+ free(w->extra);
+ w->extra = nil;
+ }else if(k == Kbs){
+ if(w->extra && runestrlen(w->extra) > 0)
+ w->extra[runestrlen(w->extra)-1] = 0;
+ }else{
+ w->p0 = w->p1 = -1;
+ Rune *tmp = w->extra;
+ if(tmp){
+ w->extra = runesmprint("%S%C", tmp, k);
+ free(tmp);
+ }else
+ w->extra = runesmprint("%C", k);
+ }
+ countlines(w);
+ scrollto(w, w->nlines);
+}
+
+void
+sessionthread(void *)
+{
+ char buf[1024];
+ sprint(buf, "/mnt/lpa/%s/cons", sessionid);
+
+ int fd = open(buf, OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+
+ for(;;){
+ memset(buf, 0, sizeof(buf));
+ if(read(fd, buf, sizeof(buf)) < 0)
+ sysfatal("read: %r");
+ Rune *text = runesmprint("%s", buf);
+ send(sessionchan, &text);
+ }
+}
+
+void
+plumbports(void)
+{
+ int fd = open("/mnt/plumb/rules", OWRITE);
+ if(fd < 0)
+ sysfatal("open: %r");
+ seek(fd, 0, 2);
+ fprint(fd, "plumb to lpaedit\n");
+ fprint(fd, "plumb to lpainfo\n");
+ close(fd);
+}
+
+void
+plumbthread(void *arg)
+{
+ Channel *c = arg;
+ char *port;
+ Plumbmsg *m;
+ int fd;
+
+ if(c == editplumbchan)
+ port = "lpaedit";
+ else
+ port = "lpainfo";
+ fd = plumbopen(port, OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ for(;;){
+ m = plumbrecv(fd);
+ if(m == nil)
+ sysfatal("plumbrecv: %r");
+ send(c, &m);
+ }
+}
+
+void
+edit(Window *w)
+{
+ if(w->type == Wsession)
+ return;
+
+ static int fd = -1;
+ if(fd < 0)
+ fd = plumbopen("send", OWRITE);
+ if(fd < 0)
+ sysfatal("plumbopen: %r");
+
+ if(plumbsendtext(fd, "lpadbg", "edit", "/", w->path) < 0)
+ sysfatal("plumb: %r");
+}
+
+char *
+menugen(int n)
+{
+ static char charbuf[256];
+ static Rune runebuf[256];
+
+ if(focusedwin == nil)
+ n += MenuMax;
+
+ switch(n){
+ case MenuResize:
+ return "Resize";
+ case MenuMaximize:
+ return "Maximize";
+ case MenuHide:
+ return "Hide";
+ case MenuClose:
+ return "Close";
+ case MenuEdit:
+ return "Edit";
+ default:
+ n -= MenuMax;
+ }
+
+ if(n < nwindows){
+ int maxlen = 0;
+ for(int i = 0; i < nwindows; i++){
+ int len = runestrlen(windowarray[i]->title);
+ if(len > maxlen)
+ maxlen = len;
+ }
+ maxlen += 2; /* for status and space */
+
+ Window *w = windowarray[n];
+ Rune state;
+ if(w == focusedwin)
+ state = L'→';
+ else if(w->hidden)
+ state = L'⋯';
+ else
+ state = L' ';
+ int len = runesnprint(runebuf, sizeof(runebuf), "%C %S", state, w->title);
+ while(len < maxlen)
+ runebuf[len++] = L' ';
+ runebuf[len] = 0;
+ snprint(charbuf, sizeof(charbuf), "%S", runebuf);
+
+ return charbuf;
+ }else
+ return nil;
+}
+
+void
+defaultwins(void)
+{
+ Rectangle r, info;
+ r = screen->r;
+
+ info = r;
+ info.min.x += Dx(r)*0.6;
+ info.min.y += Dy(r)*0.6;
+
+ infowin = addwindow(sessionid, Winfo, info);
+ infowin->hidden = 1;
+
+ r.min.x += Dx(r)*0.05;
+ r.min.y += Dy(r)*0.05;
+ r.max.x -= Dx(r)*0.5;
+ r.max.y -= Dy(r)*0.5;
+
+ sessionwin = addwindow(sessionid, Wsession, r);
+ focuswin(sessionwin);
+}
+
+void
+movewin(Window *w)
+{
+ w->hidden = 1;
+ redraw();
+ Rectangle r = w->rect;
+ do{
+ Point p = mousectl->xy;
+ drawgetrect(r, 1);
+ readmouse(mousectl);
+ drawgetrect(r, 0);
+ r = rectaddpt(r, subpt(mousectl->xy, p));
+ }while(mousectl->buttons&1);
+ w->rect = r;
+ w->hidden = 0;
+ redraw();
+}
+
+void
+scroll(Window *w, int n)
+{
+ if(w == nil)
+ return;
+ w->firstline += n;
+ if(w->firstline < 0)
+ w->firstline = 0;
+ if(w->firstline > w->nlines)
+ w->firstline = w->nlines;
+ countlines(w);
+}
+
+void
+windowselect(Window *w)
+{
+ w->p0 = w->p1 = -1;
+ redraw();
+ frselect(&w->frame, mousectl);
+ w->p0 = w->frame.p0 + w->firstchar;
+ w->p1 = w->frame.p1 + w->firstchar;
+ redraw();
+}
+
+void
+selectline(Window *w, int line)
+{
+ int start, end;
+ start = end = -1;
+
+ int offset = 0;
+ int current = 0;
+
+ Rune *strs[2] = {w->text, w->extra};
+ for(int n = 0; n < nelem(strs); n++){
+ for(Rune *r = strs[n]; r && *r; r++){
+ if(start == -1 && current == line)
+ start = offset;
+
+ offset++;
+ if(*r == '\n'){
+ current++;
+ if(start != -1){
+ end = offset;
+ goto done;
+ }
+ }
+ }
+ }
+done:
+ w->p0 = start;
+ w->p1 = end;
+
+ scrollto(w, line);
+
+ redraw();
+}
+
+void
+lpafs(void)
+{
+ int pid, ret;
+ char *name = "/bin/lpa/fs";
+ char *argv[] = {name, nil};
+
+ pid = rfork(RFPROC);
+ switch(pid){
+ case 0:
+ exec(name, argv);
+ sysfatal("exec: %r");
+ case -1:
+ sysfatal("rfork: %r");
+ default:
+ do{
+ ret = waitpid();
+ }while(ret != -1 && ret != pid);
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: lpadbg [-n id]\n");
+ exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ enum {
+ Emouse,
+ Eresize,
+ Ekeyboard,
+ Esession,
+ Eeditplumb,
+ Einfoplumb,
+ };
+ Mouse m;
+ Rune k;
+ Menu menu;
+ Window *w;
+ Rune *text;
+ Plumbmsg *p;
+
+ Alt a[] = {
+ {nil, &m, CHANRCV},
+ {nil, nil, CHANRCV},
+ {nil, &k, CHANRCV},
+ {nil, &text, CHANRCV},
+ {nil, &p, CHANRCV},
+ {nil, &p, CHANRCV},
+ {nil, nil, CHANEND},
+ };
+
+ ARGBEGIN{
+ case 'n':
+ sessionid = EARGF(usage());
+ break;
+ default:
+ usage();
+ break;
+ }ARGEND;
+ if(argc != 0)
+ usage();
+
+ lpafs();
+
+ if(sessionid == nil){
+ char buf[256] = {0};
+ int fd = open("/mnt/lpa/new", OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ if(read(fd, buf, sizeof(buf)) <= 0)
+ sysfatal("read: %r");
+ buf[strlen(buf)-1] = 0;
+ sessionid = strdup(buf);
+ close(fd);
+ }
+
+ /* make sure our plumb ports exist */
+ plumbports();
+
+ sessionchan = chancreate(sizeof(Rune *), 0);
+ editplumbchan = chancreate(sizeof(Plumbmsg *), 0);
+ infoplumbchan = chancreate(sizeof(Plumbmsg *), 0);
+ proccreate(sessionthread, nil, Stacksize);
+ proccreate(plumbthread, editplumbchan, Stacksize);
+ proccreate(plumbthread, infoplumbchan, Stacksize);
+
+ char *winname = smprint("LPA session %s", sessionid);
+ if(initdraw(nil, nil, winname) < 0)
+ sysfatal("initdraw: %r");
+ if((mousectl = initmouse(nil, screen)) == nil)
+ sysfatal("initmouse: %r");
+ if((keyboardctl = initkeyboard(nil)) == nil)
+ sysfatal("initkeyboard: %r");
+
+ a[Emouse].c = mousectl->c;
+ a[Eresize].c = mousectl->resizec;
+ a[Ekeyboard].c = keyboardctl->c;
+ a[Esession].c = sessionchan;
+ a[Eeditplumb].c = editplumbchan;
+ a[Einfoplumb].c = infoplumbchan;
+
+ menu.item = nil;
+ menu.gen = menugen;
+ menu.lasthit = 0;
+
+ defaultwins();
+ eresize(0);
+
+ for(;;){
+ int hit, wasfocused;
+ w = nil;
+ switch(alt(a)){
+ case Emouse:
+ for(Window *tmp = windows; tmp != nil; tmp = tmp->next){
+ if(!tmp->hidden && ptinrect(m.xy, tmp->rect))
+ w = tmp;
+ }
+ wasfocused = w == focusedwin;
+ if(m.buttons&7)
+ focuswin(w);
+
+ if(m.buttons&1){
+ if(w){
+ if(ptinrect(m.xy, w->frame.entire)){
+ if(wasfocused){
+ windowselect(w);
+ }
+ }else{
+ movewin(w);
+ }
+ }
+ }
+
+ if(m.buttons&4){
+ hit = menuhit(3, mousectl, &menu, nil);
+ if(focusedwin == nil && hit != -1)
+ hit += MenuMax;
+ switch(hit){
+ case MenuResize:
+ focusedwin->hidden = 1;
+ redraw();
+ resizewin(focusedwin);
+ redraw();
+ break;
+ case MenuMaximize:
+ focusedwin->rect = screen->r;
+ redraw();
+ break;
+ case MenuHide:
+ focusedwin->hidden = 1;
+ redraw();
+ break;
+ case MenuClose:
+ removewindow(focusedwin);
+ focuswin(nil);
+ break;
+ case MenuEdit:
+ edit(focusedwin);
+ break;
+ case -1:
+ break;
+ default:
+ hit -= MenuMax;
+ w = windowarray[hit];
+ focuswin(w);
+ moveto(mousectl, frptofchar(&w->frame, w->p1));
+ redraw();
+ }
+ }
+
+ if(m.buttons&8)
+ scroll(focusedwin, -1);
+ if(m.buttons&16)
+ scroll(focusedwin, 1);
+ break;
+ case Eresize:
+ eresize(1);
+ break;
+ case Ekeyboard:
+ if(focusedwin != nil)
+ inputwin(focusedwin, k);
+ break;
+ case Esession:
+ appendtext(sessionwin, text);
+ redraw();
+ break;
+ case Eeditplumb:
+ {
+ char *buf = malloc(p->ndata+1);
+ memcpy(buf, p->data, p->ndata);
+ buf[p->ndata] = 0;
+ int wintype = -1;
+
+ char *type = plumblookup(p->attr, "type");
+ char *name = plumblookup(p->attr, "name");
+ char *newwin = plumblookup(p->attr, "newwin");
+ char *session = plumblookup(p->attr, "session");
+ char *line = plumblookup(p->attr, "line");
+ int linenr = line ? atoi(line) : 0;
+
+ if(type != nil && name != nil && newwin != nil && session != nil && strcmp(session, sessionid) == 0){
+ for(int i = 0; i < Wsession; i++){
+ if(strcmp(type, typestrs[i]) == 0){
+ wintype = i;
+ break;
+ }
+ }
+ if(wintype != -1){
+ Window *w = findwindow(buf, wintype, name);
+ if(w == nil && strcmp(newwin, "yes") == 0){
+ w = addwindow(name, wintype, screen->r);
+ w->hidden = 1;
+ w->needsrect = 1;
+ w->path = strdup(buf);
+ edit(w);
+ }
+ if(w){
+ fillwindow(w);
+ if(linenr == -1)
+ w->p0 = w->p1;
+ else if(linenr > 0 && linenr <= w->nlines)
+ selectline(w, linenr-1);
+ }
+ redraw();
+ }
+ }
+ free(buf);
+ }
+ break;
+ case Einfoplumb:
+ {
+ char *session = plumblookup(p->attr, "session");
+ if(session == nil || strcmp(session, sessionid) != 0)
+ break;
+
+ char *buf = malloc(p->ndata+1);
+ memcpy(buf, p->data, p->ndata);
+ buf[p->ndata] = 0;
+
+ appendtext(infowin, runesmprint("%s\n", buf));
+ if(!infowin->needsrect)
+ focuswin(infowin);
+ free(buf);
+ }
+ break;
+ }
+ }
+}
D main.c => main.c +0 -44
@@ 1,44 0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-
-#include "dat.h"
-#include "fns.h"
-
-void
-usage(void)
-{
- fprint(2, "usage: lpafs [-D] [-n name] [-m mtpt] \n");
- exits("usage");
-}
-
-void
-threadmain(int argc, char *argv[])
-{
- char *name = "lpa";
- char *mtpt = "/mnt/lpa";
-
- ARGBEGIN{
- case 'm':
- mtpt = EARGF(usage());
- break;
- case 'n':
- name = EARGF(usage());
- break;
- case 'D':
- chatty9p++;
- break;
- default:
- usage();
- }ARGEND
- if(argc != 0)
- usage();
-
- initarrays();
- initsessions();
-
- startfs(name, mtpt);
- exits(nil);
-}>
\ No newline at end of file
M mkfile => mkfile +29 -7
@@ 1,16 1,22 @@
</$objtype/mkfile
-TARG=lpafs
-SCRIPTS=lpa
-OFILES=\
+BIN=/$objtype/bin/lpa
+TARG=\
+ fs\
+ ide\
+
+SCRIPTS=\
+ cons
+
+FS_OFILES=\
array.$O\
constraint.$O\
error.$O\
eval.$O\
fs.$O\
- main.$O\
memory.$O\
module.$O\
+ optimise.$O\
parse.$O\
prim.$O\
scan.$O\
@@ 20,20 26,36 @@ OFILES=\
util.$O\
value.$O\
+IDE_OFILES=\
+ ide.$O\
+
HFILES=\
dat.h\
fns.h\
-BIN=/$objtype/bin
+</sys/src/cmd/mkmany
+
+$O.fs: $FS_OFILES
+ $LD $LDFLAGS -o $target $prereq
+
+$O.ide: $IDE_OFILES
+ $LD $LDFLAGS -o $target $prereq
CLEANFILES=lpa.ps
default:V: all lpa.ps
install:
- cp $SCRIPTS /rc/bin/
+ mkdir -p $BIN
+ for(i in $TARG)
+ mk $MKFLAGS $i.install
+ for(i in $SCRIPTS)
+ mk $MKFLAGS $i.rcinstall
+
+%.rcinstall:V:
+ cp $stem $BIN/$stem
+ chmod +x $BIN/$stem
lpa.ps: lpa.ms
cat lpa.ms | troff -ms | lp -dstdout > $target
-</sys/src/cmd/mkone>
\ No newline at end of file
M module.c => module.c +2 -1
@@ 12,8 12,9 @@ addmodule(Session *s, char *name)
Module *m = alloc(DataModule);
m->name = strdup(name);
- m->symtab = allocsymtab();
+ m->symtab = allocsymtab(m);
m->id = id++;
+ m->session = s;
wlock(&s->modules->lock);
s->modules->count++;
A optimise.c => optimise.c +112 -0
@@ 0,0 1,112 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+
+#include "dat.h"
+#include "fns.h"
+
+static int opttailcall(ByteCode *, uvlong, u8int *);
+static int optlookup(ByteCode *, uvlong, u8int *);
+
+enum {
+ MaxPattern = 3,
+};
+
+struct {
+ int (*fn)(ByteCode *, uvlong, u8int *);
+ int count;
+ u8int instrs[MaxPattern];
+} patterns[] = {
+ {opttailcall, 2, ICall, IReturn},
+ {optlookup, 3, IAssign, IPop, ILookup},
+};
+
+void
+optimisebc(ByteCode *c, Ast *func, Symtab *symtab)
+{
+ USED(func);
+ USED(symtab);
+
+ /* Look for patterns in the byte code and replace them with
+ * something that we believe is "better" in some way.
+ */
+ u8int instrs[MaxPattern];
+ uvlong start, end, size;
+
+restart:
+ memset(instrs, 0, MaxPattern);
+ size = start = end = 0;
+ while(end < c->count){
+ if(size == MaxPattern){
+ start += instrsize(c->instrs[start]);
+ memmove(instrs, instrs+1, MaxPattern-1);
+ }else
+ size++;
+ instrs[size-1] = c->instrs[end];
+ end += instrsize(c->instrs[end]);
+
+ for(int i = 0; i < nelem(patterns); i++){
+ int matches = 1;
+ int count = patterns[i].count;
+ int offset = MaxPattern-count;
+ for(int j = 0; j < count; j++)
+ matches &= patterns[i].instrs[j] == instrs[j+offset];
+ if(!matches)
+ continue;
+ uvlong matchstart = start;
+ while(offset > 0){
+ offset--;
+ matchstart += instrsize(c->instrs[matchstart]);
+ }
+ int used = patterns[i].fn(c, matchstart, instrs);
+ if(used)
+ goto restart;
+ }
+ }
+}
+
+static void
+instrmove(ByteCode *c, uvlong dst, uvlong src)
+{
+ if(dst > src)
+ error(EInternal, "invalid dst and src given to instrmove: %ulld %ulld", dst, src);
+ uvlong count = c->count-src;
+
+ /* TODO: deal with jumps when they are added */
+ memmove(c->instrs+dst, c->instrs+src, count);
+ c->count = dst+count;
+}
+
+static int
+opttailcall(ByteCode *c, uvlong start, u8int *instrs)
+{
+ USED(instrs);
+
+ /* Change the ICall to ITailCall, and get rid of the return instruction */
+ c->instrs[start] = ITailCall;
+ instrmove(c, start+1, start+2);
+ return 1;
+}
+
+static int
+optlookup(ByteCode *c, uvlong start, u8int *instrs)
+{
+ USED(instrs);
+
+ uvlong o = start;
+ uvlong sym1, sym2;
+
+ o += 1; /* assign */
+ o += getuvlong(c->instrs+o, &sym1);
+ start = o;
+
+ o += 2; /* pop, lookup */
+ o += getuvlong(c->instrs+o, &sym2);
+
+ if(sym1 != sym2)
+ return 0;
+
+ /* Get rid of the pop and lookup instructions */
+ instrmove(c, start, o);
+ return 1;
+}<
\ No newline at end of file
M parse.c => parse.c +40 -0
@@ 66,6 66,24 @@ match(TokenList *tokens, int tag)
tokens->offset++;
}
+static int
+currentline(TokenList *tokens)
+{
+ peek(tokens);
+ return tokens->tokens[tokens->offset].line;
+}
+
+static int
+lastline(TokenList *tokens)
+{
+ int o = tokens->offset;
+ if(o > 0)
+ o--;
+ if(o >= tokens->count)
+ error(ESyntax, "unexpected end of token stream");
+ return tokens->tokens[o].line;
+}
+
static void
addchild(Ast *ast, Ast *child)
{
@@ 159,6 177,7 @@ parseprog(TokenList *t)
{
Ast *prog = alloc(DataAst);
prog->tag = AstProg;
+ prog->linestart = currentline(t);
while(peek(t) != TokEnd){
Ast *child = nil;
@@ 178,6 197,8 @@ parseprog(TokenList *t)
if(child)
addchild(prog, child);
}
+ prog->lineend = lastline(t);
+
return prog;
}
@@ 192,6 213,7 @@ parsefuncdef(TokenList *t)
parseseps(t, 1);
}
match(t, TokDel);
+ func->lineend = lastline(t);
return func;
}
@@ 201,6 223,7 @@ parsefuncheader(TokenList *t)
{
Ast *func = alloc(DataAst);
func->tag = AstFunc;
+ func->linestart = currentline(t);
match(t, TokDel);
@@ 243,12 266,15 @@ parselocals(TokenList *t)
{
Ast *locals = alloc(DataAst);
locals->tag = AstLocals;
+ locals->linestart = currentline(t);
while(peek(t) == TokSemi){
match(t, TokSemi);
Ast *name = parsename(t);
name->nameclass = NameclassLocal;
addchild(locals, name);
}
+ locals->lineend = lastline(t);
+
parseseps(t, 1);
return locals;
}
@@ 290,6 316,7 @@ parseexpr(TokenList *t, Symtab *symtab, Ast *func)
uvlong count = end-start;
Ast *later = alloc(DataAst);
later->tag = AstLater;
+ later->linestart = currentline(t);
later->tokens = alloc(DataTokenList);
later->tokens->count = count+1;
later->tokens->tokens = allocextra(later->tokens, sizeof(Token) * later->tokens->count);
@@ 298,6 325,7 @@ parseexpr(TokenList *t, Symtab *symtab, Ast *func)
match(t, peek(t));
}
later->tokens->tokens[count].tag = TokEnd;
+ later->lineend = lastline(t);
return later;
}
}
@@ 325,6 353,7 @@ again:
if(peekclass(t) == NameclassFunc){
func:
expr = alloc(DataAst);
+ expr->linestart = currentline(t);
expr->func = parsefunc(t);
if(val == nil && (isexprsep(t) || peek(t) == TokRparen))
expr->tag = AstNiladic;
@@ 336,6 365,7 @@ func:
expr->tag = AstMonadic;
expr->right = parseexprsub(t);
}
+ expr->lineend = lastline(t);
val = expr;
goto end;
}
@@ 345,9 375,11 @@ func:
if(peek(t) == TokLarrow){
match(t, TokLarrow);
expr = alloc(DataAst);
+ expr->linestart = currentline(t);
expr->tag = AstAssign;
expr->left = val;
expr->right = parseexprsub(t);
+ expr->lineend = lastline(t);
val = expr;
goto end;
}
@@ 370,8 402,10 @@ func:
if(!strand){
strand = alloc(DataAst);
strand->tag = AstStrand;
+ strand->linestart = val->linestart;
}
addchild(strand, val);
+ strand->lineend = val->lineend;
goto again;
}
@@ 389,8 423,10 @@ parsename(TokenList *t)
{
Ast *name = alloc(DataAst);
name->tag = AstName;
+ name->linestart = currentline(t);
name->name = t->tokens[t->offset].name;
match(t, TokName);
+ name->lineend = lastline(t);
return name;
}
@@ 402,9 438,11 @@ parsefunc(TokenList *t)
func = parsename(t);
else{
func = alloc(DataAst);
+ func->linestart = currentline(t);
func->tag = AstPrim;
func->prim = t->tokens[t->offset].prim;
match(t, TokPrimitive);
+ func->lineend = lastline(t);
}
return func;
@@ 414,6 452,7 @@ static Ast *
parseconst(TokenList *t)
{
Ast *val = alloc(DataAst);
+ val->linestart = currentline(t);
val->tag = AstConst;
vlong num, len;
Rune *str;
@@ 440,5 479,6 @@ parseconst(TokenList *t)
match(t, TokNumber); /* TODO: syntax error could be better here */
}
match(t, peek(t));
+ val->lineend = lastline(t);
return val;
}
M prim.c => prim.c +2 -2
@@ 100,7 100,7 @@ primid(char *s)
}
Array *
-primnilad(int id)
+primnilad(int id, Array *, Array *)
{
Array *(*fn)(void) = primspecs[id].nilad;
if(fn == nil)
@@ 109,7 109,7 @@ primnilad(int id)
}
Array *
-primmonad(int id, Array *y)
+primmonad(int id, Array *, Array *y)
{
Array *(*fn)(Array *) = primspecs[id].monad;
if(fn == nil)
M scan.c => scan.c +10 -9
@@ 6,7 6,7 @@
#include "fns.h"
Token *
-newtok(TokenList *tokens, int tag)
+newtok(TokenList *tokens, int tag, int line)
{
Token *new;
@@ 14,12 14,13 @@ newtok(TokenList *tokens, int tag)
tokens->tokens = allocextra(tokens, sizeof(Token) * tokens->count);
new = tokens->tokens + (tokens->count-1);
new->tag = tag;
+ new->line = line;
return new;
}
TokenList *
-scan(char *buf)
+scan(char *buf, int line)
{
Rune r;
int n, id;
@@ 37,19 38,19 @@ scan(char *buf)
case L']': new = TokRbrack; break;
case L'{': new = TokLbrace; break;
case L'}': new = TokRbrace; break;
- case L'\n': new = TokNewline; break;
+ case L'\n': new = TokNewline; line++; break;
case L'⋄': new = TokDiamond; break;
case L'∇': new = TokDel; break;
case L'←': new = TokLarrow; break;
case L';': new = TokSemi; break;
}
if(new != -1){
- newtok(tokens, new);
+ newtok(tokens, new, line);
goto next;
}
if((id = primid(cp)) != -1){
n = strlen(primsymb(id));
- tok = newtok(tokens, TokPrimitive);
+ tok = newtok(tokens, TokPrimitive, line);
tok->prim = id;
tok->nameclass = primclass(id);
goto next;
@@ 60,7 61,7 @@ scan(char *buf)
char *rest;
vlong num = strtoll(cp, &rest, 10);
n = rest - cp;
- tok = newtok(tokens, TokNumber);
+ tok = newtok(tokens, TokNumber, line);
tok->num = num;
goto next;
}
@@ 70,7 71,7 @@ scan(char *buf)
cp += n;
n = chartorune(&r, cp);
}while(isalpharune(r) || isdigitrune(r));
- tok = newtok(tokens, TokName);
+ tok = newtok(tokens, TokName, line);
usize size = cp - start;
tok->name = malloc(size + 1);
memcpy(tok->name, start, size);
@@ 89,7 90,7 @@ scan(char *buf)
if(r == 0)
error(ESyntax, "unmatched '");
- tok = newtok(tokens, TokString);
+ tok = newtok(tokens, TokString, line);
usize size = utfnlen(start, cp - start) + 1;
tok->string = malloc(sizeof(Rune) * size);
runesnprint(tok->string, size, "%s", start);
@@ 99,7 100,7 @@ scan(char *buf)
next:
cp += n;
}
- newtok(tokens, TokEnd);
+ newtok(tokens, TokEnd, line);
return tokens;
}
M session.c => session.c +1 -1
@@ 51,7 51,7 @@ sessionproc(void *arg)
continue;
}
- TokenList *tokens = scan(buf);
+ TokenList *tokens = scan(buf, 1); /* TODO: use actual line number */
Ast *ast = parse(tokens, 0);
eval(s, ast);
endtrap();
M symtab.c => symtab.c +11 -6
@@ 6,9 6,10 @@
#include "fns.h"
Symtab *
-allocsymtab(void)
+allocsymtab(Module *m)
{
Symtab *s = alloc(DataSymtab);
+ s->module = m;
return s;
}
@@ 74,12 75,16 @@ symptr(Symtab *s, uvlong id)
}
void
-symset(Symtab *s, uvlong id, void *newval)
+symset(Symtab *symtab, uvlong id, void *newval)
{
- wlock(&s->lock);
- s->symbols[id]->value = newval;
- s->symbols[id]->qsymbol.vers++;
- wunlock(&s->lock);
+ wlock(&symtab->lock);
+ symtab->symbols[id]->value = newval;
+ symtab->symbols[id]->qsymbol.vers++;
+ wunlock(&symtab->lock);
+
+ plumbedit(newval, symname(symtab, id), symtab->module->session, 0, 0);
+ if(newval && getalloctag(newval) == DataFunction)
+ plumbedit(((Function*)newval)->code, symname(symtab, id), symtab->module->session, 0, 0);
}
Enumeration *
M systemcmd.c => systemcmd.c +50 -19
@@ 6,8 6,10 @@
#include "dat.h"
#include "fns.h"
-char *syscmd_off(Session *, char *);
-char *syscmd_ed(Session *, char *);
+static char *syscmd_off(Session *, char *);
+static char *syscmd_ed(Session *, char *);
+static char *syscmd_bc(Session *, char *);
+static char *syscmd_trace(Session *, char *);
struct {
char *name;
@@ 15,6 17,8 @@ struct {
} cmdtab[] = {
{ "off", syscmd_off },
{ "ed", syscmd_ed },
+ { "bc", syscmd_bc },
+ { "trace", syscmd_trace },
};
void
@@ 37,9 41,14 @@ systemcmd(Session *s, char *cmd, int ctl)
if(strcmp(cmdtab[i].name, parts[0]) == 0)
fn = cmdtab[i].fn;
- if(fn != nil)
- out = fn(s, parts[1]);
- else
+ if(fn != nil){
+ if(trap(EAny))
+ out = strdup(errmsg());
+ else{
+ out = fn(s, parts[1]);
+ endtrap();
+ }
+ }else
out = smprint("invalid system command: %s", parts[0]);
if(!ctl && out){
@@ 49,7 58,7 @@ systemcmd(Session *s, char *cmd, int ctl)
free(out);
}
-char *
+static char *
syscmd_off(Session *s, char *args)
{
if(strcmp(args, "") != 0)
@@ 61,22 70,44 @@ syscmd_off(Session *s, char *args)
return smprint("bye bye :)");
}
-char *
+static char *
syscmd_ed(Session *s, char *name)
{
- char *resp = nil;
- int fd = plumbopen("send", OWRITE);
- if(fd < 0)
- return smprint("plumb failed: %r");
trim(name);
/* create the symbol */
- sym(s->modules->modules[0]->symtab, name); /* TODO: fix this and the line below. Name and module should be parsed.. */
-
- char *path = smprint("/mnt/lpa/%ulld/modules/main/%s", s->id, name);
- if(plumbsendtext(fd, "lpa", "edit", "/", path) < 0)
- resp = smprint("plumb failed: %r");
- close(fd);
- free(path);
- return resp;
+ uvlong symid = sym(s->modules->modules[0]->symtab, name); /* TODO: fix this and the line below. Name and module should be parsed.. */
+
+ void *val = symval(s->modules->modules[0]->symtab, symid);
+ plumbedit(val, name, s, 1, 0);
+ return nil;
+}
+
+static char *
+syscmd_bc(Session *s, char *name)
+{
+ trim(name);
+
+ /* create the symbol */
+ uvlong symid = sym(s->modules->modules[0]->symtab, name); /* TODO: fix this and the line below. Name and module should be parsed.. */
+
+ void *val = symval(s->modules->modules[0]->symtab, symid);
+ if(val == nil || getalloctag(val) != DataFunction)
+ error(EDomain, "%s is not a function", name);
+ val = ((Function*)val)->code;
+ plumbedit(val, name, s, 1, 0);
+ return nil;
+}
+
+static char *
+syscmd_trace(Session *s, char *val)
+{
+ trim(val);
+ if(strcmp(val, "on") == 0)
+ s->debugtrace = 1;
+ else if(strcmp(val, "off") == 0)
+ s->debugtrace = 0;
+ else
+ return smprint("unknown )trace mode: \"%s\"", val);
+ return nil;
}=
\ No newline at end of file
M util.c => util.c +175 -20
@@ 1,6 1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
+#include <plumb.h>
#include "dat.h"
#include "fns.h"
@@ 131,73 132,155 @@ getuvlong(u8int *p, uvlong *vp)
return size;
}
-void
-debugbc(ByteCode *c)
+char *
+printbc(ByteCode *c)
{
- uvlong o, v;
+ static char buf[4096]; /* TODO: fixed size :) */
+
+ uvlong o, v, v2;
+
+ int nlines = 0;
+ struct line {
+ char *istr;
+ char *a1str;
+ char *a2str;
+ char *comment;
+ } *lines = nil;
o = 0;
while(o < c->count){
int instr = c->instrs[o];
o++;
+ nlines++;
+ lines = realloc(lines, sizeof(*lines) * nlines);
+ struct line *l = &lines[nlines-1];
+ memset(l, 0, sizeof(struct line));
+
switch(instr){
case IPushConst:
o += getuvlong(c->instrs+o, &v);
- print("CONST %p\n", (void*)v);
+ l->istr = smprint("CONST");
+ l->a1str = smprint("%p", (void*)v);
break;
case IPushPrim:
o += getuvlong(c->instrs+o, &v);
- print("PRIM %p\n", v);
+ l->istr = smprint("PRIM");
+ l->a1str = smprint("%p", (void*)v);
+ l->comment = smprint("%s", primsymb(v));
break;
case ILookup:
o += getuvlong(c->instrs+o, &v);
- print("LOOKUP %ulld\n", v);
+ l->istr = smprint("LOOKUP");
+ l->a1str = smprint("%ulld", v);
+ l->comment = smprint("%s", symname(c->module->symtab, v));
break;
case IStrand:
o += getuvlong(c->instrs+o, &v);
- print("STRAND %ulld\n", v);
+ l->istr = smprint("STRAND");
+ l->a1str = smprint("%ulld", v);
break;
case INiladic:
- print("NILADIC CALL\n");
+ l->istr = smprint("NILADIC_CHECK");
break;
case IMonadic:
- print("MONADIC CALL\n");
+ l->istr = smprint("MONADIC_CHECK");
break;
case IDyadic:
- print("DYADIC CALL\n");
+ l->istr = smprint("DYADIC_CHECK");
+ break;
+ case ICall:
+ l->istr = smprint("CALL");
+ break;
+ case ITailCall:
+ l->istr = smprint("TAILCALL");
break;
case IParse:
o += getuvlong(c->instrs+o, &v);
- print("PARSE %ulld\n", v);
+ o += getuvlong(c->instrs+o, &v2);
+ l->istr = smprint("PARSE");
+ l->a1str = smprint("%ulld", v);
+ l->a2str = smprint("%ulld", v2);
break;
case IReturn:
- print("RETURN\n");
+ l->istr = smprint("RETURN");
break;
case IAssign:
o += getuvlong(c->instrs+o, &v);
- print("ASSIGN %ulld\n", v);
+ l->istr = smprint("ASSIGN");
+ l->a1str = smprint("%ulld", v);
+ l->comment = smprint("%s", symname(c->module->symtab, v));
break;
case ILocal:
o += getuvlong(c->instrs+o, &v);
- print("LOCAL %ulld\n", v);
+ l->istr = smprint("LOCAL");
+ l->a1str = smprint("%ulld", v);
+ l->comment = smprint("%s", symname(c->module->symtab, v));
break;
case IPop:
- print("POP\n");
+ l->istr = smprint("POP");
break;
case IDisplay:
- print("DISPLAY\n");
+ l->istr = smprint("DISPLAY");
break;
case IPushVar:
o += getuvlong(c->instrs+o, &v);
- print("PUSHVAR %ulld\n", v);
+ l->istr = smprint("PUSHVAR");
+ l->a1str = smprint("%ulld", v);
+ l->comment = smprint("%s", symname(c->module->symtab, v));
+ break;
+ case IFuncres:
+ o += getuvlong(c->instrs+o, &v);
+ l->istr = smprint("FUNCRES");
+ l->a1str = smprint("%ulld", v);
+ break;
+ case ILine:
+ o += getuvlong(c->instrs+o, &v);
+ l->istr = smprint("LINE");
+ l->a1str = smprint("%ulld", v);
+ l->comment = smprint("wouldn't it be nice to have the line of code here?");
break;
default:
- print("???");
- return;
+ error(EInternal, "unknown instruction in printbc: %d", instr);
}
}
- print("\n");
+
+ int maxistr, maxa1str, maxa2str;
+ maxistr = maxa1str = maxa2str = 0;
+
+ for(int i = 0; i < nlines; i++){
+ struct line *l = &lines[i];
+ long len;
+ if(l->istr && (len = strlen(l->istr)) > maxistr)
+ maxistr = len;
+ if(l->a1str && (len = strlen(l->a1str)) > maxa1str)
+ maxa1str = len;
+ if(l->a2str && (len = strlen(l->a2str)) > maxa2str)
+ maxa2str = len;
+ }
+
+ char *fmt = smprint("%%-%ds %%-%ds%%s %%-%ds%%s%%s\n", maxistr, maxa1str, maxa2str);
+
+ char *p = buf;
+ for(int i = 0; i < nlines; i++){
+ struct line *l = &lines[i];
+ p += snprint(p, sizeof(buf), fmt,
+ l->istr,
+ l->a1str ? l->a1str : "",
+ l->a2str ? "," : " ",
+ l->a2str ? l->a2str : "",
+ l->comment ? " ⍝ " : "",
+ l->comment ? l->comment : ""
+ );
+
+ free(l->istr);
+ free(l->a1str);
+ free(l->a2str);
+ free(l->comment);
+ }
+ free(lines);
+
+ return buf;
}
char *
@@ 207,4 290,76 @@ funcname(Function *f)
return f->ast->funcname->name;
else
return primsymb(f->prim);
+}
+
+void
+plumbedit(void *val, char *name, Session *s, int newwin, int line)
+{
+ static int fd = -1;
+ int bc = 0;
+
+ if(fd < 0)
+ fd = plumbopen("send", OWRITE);
+ if(fd < 0)
+ error(EInternal, "plumb failed: %r");
+
+ char *type = "undefined";
+ if(val) switch(getalloctag(val)){
+ case DataFunction:
+ type = "function";
+ break;
+ case DataArray:
+ type = "array";
+ break;
+ case DataByteCode:
+ bc = 1;
+ type = "bytecode";
+ break;
+ }
+ char *path = smprint("/mnt/lpa/%ulld/modules/main/%s%s", s->id, name, bc ? ".bc" : "");
+ char *lineinfo = (line != 0) ? smprint("line=%d", line) : smprint("");
+ char *attrs = smprint("type=%s name=%s session=%ulld newwin=%s %s", type, name, s->id, newwin ? "yes" : "no", lineinfo);
+
+ Plumbmsg m;
+
+ m.src = "lpa";
+ m.dst = "lpaedit";
+ m.wdir = "/";
+ m.type = "text";
+ m.attr = plumbunpackattr(attrs);
+ m.ndata = strlen(path);
+ m.data = path;
+
+ if(plumbsend(fd, &m) < 0)
+ error(EInternal, "plumb failed: %r");
+ free(path);
+ free(attrs);
+ free(lineinfo);
+}
+
+void
+plumbinfo(Session *s, char *msg)
+{
+ static int fd = -1;
+
+ if(fd < 0)
+ fd = plumbopen("send", OWRITE);
+ if(fd < 0)
+ error(EInternal, "plumb failed: %r");
+
+ char *attrs = smprint("session=%ulld", s->id);
+ Plumbmsg m;
+
+ m.src = "lpa";
+ m.dst = "lpainfo";
+ m.wdir = "/";
+ m.type = "text";
+ m.attr = plumbunpackattr(attrs);
+ m.ndata = strlen(msg);
+ m.data = msg;
+
+ if(plumbsend(fd, &m) < 0)
+ error(EInternal, "plumb failed: %r");
+ free(attrs);
+
}=
\ No newline at end of file
M value.c => value.c +6 -4
@@ 17,14 17,16 @@ printval(void *v)
tag = getalloctag(v);
switch(tag){
case DataArray:
- return smprint("%s\n", printarray(v));
+ return smprint("%s", printarray(v));
case DataFunction:
- return smprint("%s\n", printfunc(v));
+ return smprint("%s", printfunc(v));
+ case DataByteCode:
+ return smprint("%s", printbc(v));
default:
return smprint("some value of type %d\n", tag);
}
}else
- return smprint("no value :(\n");
+ return smprint("");
}
void *
@@ 33,7 35,7 @@ parseval(Session *s, char *buf)
Ast *ast;
void *val;
- TokenList *tokens = scan(buf);
+ TokenList *tokens = scan(buf, 1);
ast = parse(tokens, nil);
if(!(ast->tag == AstProg && ast->childcount == 1))