forked from OctaForge/libcubescript
more progress
parent
85f3bf6ce3
commit
c785d03208
146
command.cc
146
command.cc
|
@ -83,7 +83,7 @@ Ident *CsState::new_ident(ostd::ConstCharRange name, int flags) {
|
||||||
Ident *id = idents.at(name);
|
Ident *id = idents.at(name);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
if (check_num(name.data())) {
|
if (check_num(name.data())) {
|
||||||
debug_code("number %.*s is not a valid identifier name", int(name.size()), name.data());
|
debug_code("number %s is not a valid identifier name", name);
|
||||||
return dummy;
|
return dummy;
|
||||||
}
|
}
|
||||||
id = add_ident(ID_ALIAS, name, flags);
|
id = add_ident(ID_ALIAS, name, flags);
|
||||||
|
@ -117,7 +117,7 @@ bool CsState::reset_var(ostd::ConstCharRange name) {
|
||||||
Ident *id = idents.at(name);
|
Ident *id = idents.at(name);
|
||||||
if (!id) return false;
|
if (!id) return false;
|
||||||
if (id->flags & IDF_READONLY) {
|
if (id->flags & IDF_READONLY) {
|
||||||
debug_code("variable %s is read only", id->name.data());
|
debug_code("variable %s is read only", id->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
clear_override(*id);
|
clear_override(*id);
|
||||||
|
@ -135,6 +135,36 @@ void CsState::touch_var(ostd::ConstCharRange name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CsState::set_alias(ostd::ConstCharRange name, TaggedValue &v) {
|
||||||
|
Ident *id = cstate.idents.at(name);
|
||||||
|
if (id) {
|
||||||
|
switch (id->type) {
|
||||||
|
case ID_ALIAS:
|
||||||
|
if (id->index < MAX_ARGUMENTS) id->set_arg(cstate, v);
|
||||||
|
else id->set_alias(cstate, v);
|
||||||
|
return;
|
||||||
|
case ID_VAR:
|
||||||
|
setvarchecked(id, v.get_int());
|
||||||
|
break;
|
||||||
|
case ID_FVAR:
|
||||||
|
setfvarchecked(id, v.get_float());
|
||||||
|
break;
|
||||||
|
case ID_SVAR:
|
||||||
|
setsvarchecked(id, v.get_str());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cstate.debug_code("cannot redefine builtin %s with an alias", id->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v.cleanup();
|
||||||
|
} else if (check_num(name.data())) {
|
||||||
|
cstate.debug_code("cannot alias number %s", name);
|
||||||
|
v.cleanup();
|
||||||
|
} else {
|
||||||
|
cstate.add_ident(ID_ALIAS, name, v, cstate.identflags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int _numargs = variable("numargs", MAX_ARGUMENTS, 0, 0, &_numargs, nullptr, 0);
|
int _numargs = variable("numargs", MAX_ARGUMENTS, 0, 0, &_numargs, nullptr, 0);
|
||||||
|
|
||||||
void TaggedValue::cleanup() {
|
void TaggedValue::cleanup() {
|
||||||
|
@ -333,6 +363,24 @@ void Ident::pop_alias() {
|
||||||
if (type == ID_ALIAS && index >= MAX_ARGUMENTS) pop_arg();
|
if (type == ID_ALIAS && index >= MAX_ARGUMENTS) pop_arg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ident::set_arg(CsState &cs, TaggedValue &v) {
|
||||||
|
if (cs.stack->usedargs & (1 << index)) {
|
||||||
|
if (valtype == VAL_STR) delete[] val.s;
|
||||||
|
setval(v);
|
||||||
|
clean_code();
|
||||||
|
} else {
|
||||||
|
push_arg(v, cs.stack->argstack[index]);
|
||||||
|
cs.stack->usedargs |= 1 << index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ident::set_alias(CsState &cs, TaggedValue &v) {
|
||||||
|
if (valtype == VAL_STR) delete[] val.s;
|
||||||
|
setval(v);
|
||||||
|
clean_code();
|
||||||
|
flags = (flags & cs.identflags) | cs.identflags;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
static void cs_do_args(CsState &cs, F body) {
|
static void cs_do_args(CsState &cs, F body) {
|
||||||
IdentStack argstack[MAX_ARGUMENTS];
|
IdentStack argstack[MAX_ARGUMENTS];
|
||||||
|
@ -377,66 +425,8 @@ void init_lib_base(CsState &cs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setarg(Ident &id, TaggedValue &v) {
|
ICOMMAND(alias, "sT", (CsState &cs, const char *name, TaggedValue *v), {
|
||||||
if (cstate.stack->usedargs & (1 << id.index)) {
|
cs.set_alias(name, *v);
|
||||||
if (id.valtype == VAL_STR) delete[] id.val.s;
|
|
||||||
id.setval(v);
|
|
||||||
id.clean_code();
|
|
||||||
} else {
|
|
||||||
id.push_arg(v, cstate.stack->argstack[id.index]);
|
|
||||||
cstate.stack->usedargs |= 1 << id.index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void setalias(Ident &id, TaggedValue &v) {
|
|
||||||
if (id.valtype == VAL_STR) delete[] id.val.s;
|
|
||||||
id.setval(v);
|
|
||||||
id.clean_code();
|
|
||||||
id.flags = (id.flags & cstate.identflags) | cstate.identflags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setalias(const char *name, TaggedValue &v) {
|
|
||||||
Ident *id = cstate.idents.at(name);
|
|
||||||
if (id) {
|
|
||||||
switch (id->type) {
|
|
||||||
case ID_ALIAS:
|
|
||||||
if (id->index < MAX_ARGUMENTS) setarg(*id, v);
|
|
||||||
else setalias(*id, v);
|
|
||||||
return;
|
|
||||||
case ID_VAR:
|
|
||||||
setvarchecked(id, v.get_int());
|
|
||||||
break;
|
|
||||||
case ID_FVAR:
|
|
||||||
setfvarchecked(id, v.get_float());
|
|
||||||
break;
|
|
||||||
case ID_SVAR:
|
|
||||||
setsvarchecked(id, v.get_str());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cstate.debug_code("cannot redefine builtin %s with an alias", id->name.data());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v.cleanup();
|
|
||||||
} else if (check_num(name)) {
|
|
||||||
cstate.debug_code("cannot alias number %s", name);
|
|
||||||
v.cleanup();
|
|
||||||
} else {
|
|
||||||
cstate.add_ident(ID_ALIAS, name, v, cstate.identflags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void alias(const char *name, const char *str) {
|
|
||||||
TaggedValue v;
|
|
||||||
v.set_str(dup_ostr(str));
|
|
||||||
setalias(name, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void alias(const char *name, TaggedValue &v) {
|
|
||||||
setalias(name, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
ICOMMAND(alias, "sT", (CsState &, const char *name, TaggedValue *v), {
|
|
||||||
setalias(name, *v);
|
|
||||||
v->type = VAL_NULL;
|
v->type = VAL_NULL;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -445,16 +435,6 @@ int variable(const char *name, int min, int cur, int max, int *storage, IdentFun
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fvariable(const char *name, float min, float cur, float max, float *storage, IdentFunc fun, int flags) {
|
|
||||||
cstate.add_ident(ID_FVAR, name, min, max, storage, fun, flags);
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *svariable(const char *name, const char *cur, char **storage, IdentFunc fun, int flags) {
|
|
||||||
cstate.add_ident(ID_SVAR, name, storage, fun, flags);
|
|
||||||
return dup_ostr(cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define _GETVAR(id, vartype, name, retval) \
|
#define _GETVAR(id, vartype, name, retval) \
|
||||||
Ident *id = cstate.idents.at(name); \
|
Ident *id = cstate.idents.at(name); \
|
||||||
if(!id || id->type!=vartype) return retval;
|
if(!id || id->type!=vartype) return retval;
|
||||||
|
@ -464,7 +444,7 @@ char *svariable(const char *name, const char *cur, char **storage, IdentFunc fun
|
||||||
{ \
|
{ \
|
||||||
if(id->flags&IDF_PERSIST) \
|
if(id->flags&IDF_PERSIST) \
|
||||||
{ \
|
{ \
|
||||||
cstate.debug_code("cannot override persistent variable %s", id->name.data()); \
|
cstate.debug_code("cannot override persistent variable %s", id->name); \
|
||||||
errorval; \
|
errorval; \
|
||||||
} \
|
} \
|
||||||
if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \
|
if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \
|
||||||
|
@ -538,12 +518,12 @@ int clampvar(Ident *id, int val, int minval, int maxval) {
|
||||||
cstate.debug_code(id->flags & IDF_HEX ?
|
cstate.debug_code(id->flags & IDF_HEX ?
|
||||||
(minval <= 255 ? "valid range for %s is %d..0x%X" : "valid range for %s is 0x%X..0x%X") :
|
(minval <= 255 ? "valid range for %s is %d..0x%X" : "valid range for %s is 0x%X..0x%X") :
|
||||||
"valid range for %s is %d..%d",
|
"valid range for %s is %d..%d",
|
||||||
id->name.data(), minval, maxval);
|
id->name, minval, maxval);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setvarchecked(Ident *id, int val) {
|
void setvarchecked(Ident *id, int val) {
|
||||||
if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name.data());
|
if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name);
|
||||||
else {
|
else {
|
||||||
OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
|
OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
|
||||||
if (val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval);
|
if (val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval);
|
||||||
|
@ -565,12 +545,12 @@ float clampfvar(Ident *id, float val, float minval, float maxval) {
|
||||||
if (val < minval) val = minval;
|
if (val < minval) val = minval;
|
||||||
else if (val > maxval) val = maxval;
|
else if (val > maxval) val = maxval;
|
||||||
else return val;
|
else return val;
|
||||||
cstate.debug_code("valid range for %s is %s..%s", id->name.data(), floatstr(minval), floatstr(maxval));
|
cstate.debug_code("valid range for %s is %s..%s", id->name, floatstr(minval), floatstr(maxval));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setfvarchecked(Ident *id, float val) {
|
void setfvarchecked(Ident *id, float val) {
|
||||||
if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name.data());
|
if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name);
|
||||||
else {
|
else {
|
||||||
OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
|
OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
|
||||||
if (val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf);
|
if (val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf);
|
||||||
|
@ -580,7 +560,7 @@ void setfvarchecked(Ident *id, float val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setsvarchecked(Ident *id, const char *val) {
|
void setsvarchecked(Ident *id, const char *val) {
|
||||||
if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name.data());
|
if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name);
|
||||||
else {
|
else {
|
||||||
OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] * id->storage.s);
|
OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] * id->storage.s);
|
||||||
*id->storage.s = dup_ostr(val);
|
*id->storage.s = dup_ostr(val);
|
||||||
|
@ -2621,7 +2601,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
|
||||||
case CODE_LOOKUP|RET_STR:
|
case CODE_LOOKUP|RET_STR:
|
||||||
#define LOOKUP(aval) { \
|
#define LOOKUP(aval) { \
|
||||||
Ident *id = cstate.identmap[op>>8]; \
|
Ident *id = cstate.identmap[op>>8]; \
|
||||||
if(id->flags&IDF_UNKNOWN) cstate.debug_code("unknown alias lookup: %s", id->name.data()); \
|
if(id->flags&IDF_UNKNOWN) cstate.debug_code("unknown alias lookup: %s", id->name); \
|
||||||
aval; \
|
aval; \
|
||||||
continue; \
|
continue; \
|
||||||
}
|
}
|
||||||
|
@ -2814,14 +2794,14 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case CODE_ALIAS:
|
case CODE_ALIAS:
|
||||||
setalias(*cstate.identmap[op >> 8], args[--numargs]);
|
cstate.identmap[op >> 8]->set_alias(cstate, args[--numargs]);
|
||||||
continue;
|
continue;
|
||||||
case CODE_ALIASARG:
|
case CODE_ALIASARG:
|
||||||
setarg(*cstate.identmap[op >> 8], args[--numargs]);
|
cstate.identmap[op >> 8]->set_arg(cstate, args[--numargs]);
|
||||||
continue;
|
continue;
|
||||||
case CODE_ALIASU:
|
case CODE_ALIASU:
|
||||||
numargs -= 2;
|
numargs -= 2;
|
||||||
setalias(args[numargs].get_str(), args[numargs + 1]);
|
cstate.set_alias(args[numargs].get_str(), args[numargs + 1]);
|
||||||
args[numargs].cleanup();
|
args[numargs].cleanup();
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -2865,7 +2845,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
|
||||||
Ident *id = cstate.identmap[op >> 13];
|
Ident *id = cstate.identmap[op >> 13];
|
||||||
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
|
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
|
||||||
if (id->flags & IDF_UNKNOWN) {
|
if (id->flags & IDF_UNKNOWN) {
|
||||||
cstate.debug_code("unknown command: %s", id->name.data());
|
cstate.debug_code("unknown command: %s", id->name);
|
||||||
FORCERESULT;
|
FORCERESULT;
|
||||||
}
|
}
|
||||||
CALLALIAS;
|
CALLALIAS;
|
||||||
|
|
|
@ -285,6 +285,9 @@ struct Ident {
|
||||||
|
|
||||||
void push_alias(IdentStack &st);
|
void push_alias(IdentStack &st);
|
||||||
void pop_alias();
|
void pop_alias();
|
||||||
|
|
||||||
|
void set_arg(CsState &cs, TaggedValue &v);
|
||||||
|
void set_alias(CsState &cs, TaggedValue &v);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IdentLink {
|
struct IdentLink {
|
||||||
|
@ -390,6 +393,8 @@ struct CsState {
|
||||||
ostd::forward<A>(args)...);
|
ostd::forward<A>(args)...);
|
||||||
debug_alias(*this);
|
debug_alias(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_alias(ostd::ConstCharRange name, TaggedValue &v);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CsState cstate;
|
extern CsState cstate;
|
||||||
|
@ -528,8 +533,6 @@ inline void Ident::getcval(TaggedValue &v) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int variable(const char *name, int min, int cur, int max, int *storage, IdentFunc fun, int flags);
|
extern int variable(const char *name, int min, int cur, int max, int *storage, IdentFunc fun, int flags);
|
||||||
extern float fvariable(const char *name, float min, float cur, float max, float *storage, IdentFunc fun, int flags);
|
|
||||||
extern char *svariable(const char *name, const char *cur, char **storage, IdentFunc fun, int flags);
|
|
||||||
extern void setvar(const char *name, int i, bool dofunc = true, bool doclamp = true);
|
extern void setvar(const char *name, int i, bool dofunc = true, bool doclamp = true);
|
||||||
extern void setfvar(const char *name, float f, bool dofunc = true, bool doclamp = true);
|
extern void setfvar(const char *name, float f, bool dofunc = true, bool doclamp = true);
|
||||||
extern void setsvar(const char *name, const char *str, bool dofunc = true);
|
extern void setsvar(const char *name, const char *str, bool dofunc = true);
|
||||||
|
@ -546,8 +549,6 @@ extern void freecode(ostd::uint *p);
|
||||||
extern void executeret(const ostd::uint *code, TaggedValue &result = *cstate.result);
|
extern void executeret(const ostd::uint *code, TaggedValue &result = *cstate.result);
|
||||||
extern void executeret(const char *p, TaggedValue &result = *cstate.result);
|
extern void executeret(const char *p, TaggedValue &result = *cstate.result);
|
||||||
extern void executeret(Ident *id, TaggedValue *args, int numargs, TaggedValue &result = *cstate.result);
|
extern void executeret(Ident *id, TaggedValue *args, int numargs, TaggedValue &result = *cstate.result);
|
||||||
extern void alias(const char *name, const char *action);
|
|
||||||
extern void alias(const char *name, TaggedValue &v);
|
|
||||||
extern const char *getalias(const char *name);
|
extern const char *getalias(const char *name);
|
||||||
extern const char *escapestring(const char *s);
|
extern const char *escapestring(const char *s);
|
||||||
extern const char *escapeid(const char *s);
|
extern const char *escapeid(const char *s);
|
||||||
|
|
Loading…
Reference in New Issue