update sigh
This commit is contained in:
+2
-1
@@ -29,7 +29,8 @@ RENDER()
|
||||
<li><a href="shell.uce">Shell</a></li>
|
||||
<li><a href="file_append.uce">File Append</a></li>
|
||||
<li><a href="random.uce">RNG/Noise</a></li>
|
||||
<li><a href="task.uce">Task API</a></li>
|
||||
<li><a href="task.uce">Task</a></li>
|
||||
<li><a href="task_repeat.uce">Task repeat</a></li>
|
||||
<li><a href="utf8.uce">UTF-8</a></li>
|
||||
<li><a href="call_file.uce">call_file()</a></li>
|
||||
</ul>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
|
||||
void show_form()
|
||||
EXPORT void show_form()
|
||||
{
|
||||
|
||||
<><form action="?" method="post">
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
v1 : string = "";
|
||||
|
||||
v2 = 'BLA';
|
||||
v2 := 'BLA';
|
||||
i1 := 123.2;
|
||||
|
||||
for(v3 => c);
|
||||
for(v3 => c)
|
||||
print(c);
|
||||
|
||||
v1 = "This is an interpolated string {=i1}
|
||||
which also contains line breaks";
|
||||
|
||||
?><div>
|
||||
It's now time for some HTML!
|
||||
</div>
|
||||
<?
|
||||
|
||||
print("And, we're back!");
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
+84
-310
@@ -1,332 +1,114 @@
|
||||
enum TokenType{ TT_UNKNOWN, TT_STRING, TT_INT, TT_FLOAT, TT_IDENTIFIER, TT_OPERATOR };
|
||||
String TokenTypeName[] = { "TT_UNKNOWN", "TT_STRING", "TT_INT", "TT_FLOAT", "TT_IDENTIFIER", "TT_OPERATOR" };
|
||||
|
||||
String add_token_type(String tokenstr)
|
||||
struct Token
|
||||
{
|
||||
char c = tokenstr[0];
|
||||
if(c == 34) // quote character, as number here because of HTML parser bug
|
||||
return(String("Q") + tokenstr);
|
||||
if(isalpha(c))
|
||||
return(String("I") + tokenstr);
|
||||
if(isdigit(c))
|
||||
return(String("N") + tokenstr);
|
||||
if(ispunct(c))
|
||||
return(String("O") + tokenstr);
|
||||
return(String("?") + tokenstr);
|
||||
}
|
||||
String literal = "";
|
||||
TokenType type = TT_UNKNOWN;
|
||||
char delim = ' ';
|
||||
};
|
||||
|
||||
StringList script_tokenize(String code)
|
||||
#define NEW_TOKEN { result.push_back(ctok); ctok = new Token(); goto eval_char; }
|
||||
|
||||
std::vector<Token*> script_tokenize(String code)
|
||||
{
|
||||
StringList result;
|
||||
String current_token = "";
|
||||
char mode = 'N';
|
||||
char quote_character = 0;
|
||||
char last_character = 0;
|
||||
std::vector<Token*> result;
|
||||
auto ctok = new Token();
|
||||
|
||||
for(auto c : code)
|
||||
{
|
||||
if(mode == 'Q')
|
||||
{
|
||||
if(c == '\\')
|
||||
{
|
||||
|
||||
}
|
||||
else if(quote_character == c && last_character != '\\')
|
||||
{
|
||||
mode = 'N';
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
current_token.append(1, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
eval_char:
|
||||
if(ctok->type == TT_UNKNOWN)
|
||||
{
|
||||
if(isspace(c))
|
||||
{
|
||||
if(current_token != "")
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "";
|
||||
|
||||
}
|
||||
else if(isdigit(c))
|
||||
{
|
||||
ctok->type = TT_INT;
|
||||
}
|
||||
else if(isalpha(c))
|
||||
{
|
||||
ctok->type = TT_IDENTIFIER;
|
||||
}
|
||||
else if(c == '"' || c == '\'')
|
||||
{
|
||||
mode = 'Q';
|
||||
quote_character = c;
|
||||
if(current_token != "")
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "\"";
|
||||
ctok->type = TT_STRING;
|
||||
ctok->delim = c;
|
||||
continue;
|
||||
}
|
||||
else if(ispunct(c) && c != '_')
|
||||
else if(ispunct(c))
|
||||
{
|
||||
if(current_token != "")
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "";
|
||||
result.push_back(add_token_type(String("").append(1, c)));
|
||||
ctok->type = TT_OPERATOR;
|
||||
}
|
||||
else
|
||||
}
|
||||
switch(ctok->type)
|
||||
{
|
||||
case(TT_IDENTIFIER):
|
||||
{
|
||||
current_token.append(1, c);
|
||||
if(isalnum(c) || c == '_')
|
||||
ctok->literal += c;
|
||||
else
|
||||
NEW_TOKEN
|
||||
break;
|
||||
}
|
||||
}
|
||||
last_character = c;
|
||||
}
|
||||
if(current_token != "")
|
||||
result.push_back(add_token_type(current_token));
|
||||
return(result);
|
||||
}
|
||||
|
||||
struct ASTNode
|
||||
{
|
||||
String identifier = "";
|
||||
String type_name = "";
|
||||
String string_literal = "";
|
||||
char type = 0;
|
||||
std::vector<ASTNode*> assign;
|
||||
std::vector<ASTNode*> call_params;
|
||||
std::vector<ASTNode*> children;
|
||||
|
||||
ASTNode(char _type)
|
||||
{
|
||||
identifier = "";
|
||||
type_name = "";
|
||||
string_literal = "";
|
||||
type = _type;
|
||||
}
|
||||
|
||||
String to_string(String indent = "")
|
||||
{
|
||||
String result = "";
|
||||
result += indent + String().append(1, type);
|
||||
if(identifier != "")
|
||||
result += " ident=" + identifier;
|
||||
if(type_name != "")
|
||||
result += " type_name=" + type_name;
|
||||
if(string_literal != "")
|
||||
result += " " + string_literal;
|
||||
result += "\n";
|
||||
for(auto callp : call_params)
|
||||
result += indent + " CALLP " + callp->to_string(indent + " ");
|
||||
for(auto assign_expr : assign)
|
||||
result += indent + " ASSIGN VALUE " + assign_expr->to_string(indent + " ");
|
||||
for(auto child : children)
|
||||
result += indent + " " + child->to_string(indent + " ");
|
||||
return(result);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct ParserState
|
||||
{
|
||||
|
||||
ASTNode* root;
|
||||
StringList tokens;
|
||||
s32 token_index = 0;
|
||||
String error = "";
|
||||
u64 error_location = 0;
|
||||
|
||||
String consume(char token_kind = 0)
|
||||
{
|
||||
if(error_location > 0) return("");
|
||||
if(token_kind && look_ahead(0)[0] != token_kind)
|
||||
{
|
||||
unexpected_token();
|
||||
}
|
||||
printf("consume #%i %s -> %s \n", token_index, look_ahead(0).c_str(), look_ahead(1).c_str());
|
||||
String tk = look_ahead(0);
|
||||
token_index++;
|
||||
return(tk);
|
||||
}
|
||||
|
||||
String look_ahead(s32 by)
|
||||
{
|
||||
if(error_location > 0)
|
||||
return("_");
|
||||
if(token_index+by < 0 || token_index+by >= tokens.size())
|
||||
return("_");
|
||||
return(tokens[token_index+by]);
|
||||
}
|
||||
|
||||
bool more()
|
||||
{
|
||||
if(error_location > 0)
|
||||
return(false);
|
||||
return(token_index < tokens.size());
|
||||
}
|
||||
|
||||
void unexpected_token(s32 offset = 0)
|
||||
{
|
||||
if(error_location) return;
|
||||
String found = look_ahead(offset);
|
||||
error_location = token_index;
|
||||
token_index = tokens.size() + 1;
|
||||
error = String("unexpected '") + found.substr(1) + String("' found");
|
||||
}
|
||||
|
||||
bool expect(String token_str, String in_mode)
|
||||
{
|
||||
if(error_location) return(false);
|
||||
String found = look_ahead(0);
|
||||
if(found == token_str)
|
||||
{
|
||||
consume();
|
||||
return(true);
|
||||
}
|
||||
error_location = token_index;
|
||||
token_index = tokens.size() + 1;
|
||||
error = String("'") + token_str.substr(1) + "' expected but '" + found.substr(1) + "' found in "+in_mode.substr(1);
|
||||
return(false);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ASTNode* script_parse_expression(ParserState* state, String delim1, String delim2);
|
||||
ASTNode* script_parse_declaration(ParserState* state, String delim1, String delim2);
|
||||
|
||||
ASTNode* script_parse_declaration(ParserState* state, String delim1, String delim2)
|
||||
{
|
||||
ASTNode* result = new ASTNode('D');
|
||||
|
||||
String ident = state->consume();
|
||||
if(ident[0] != 'I')
|
||||
{
|
||||
state->unexpected_token(-1);
|
||||
return(result);
|
||||
}
|
||||
result->identifier = ident.substr(1);
|
||||
|
||||
if(!state->expect("O:", "declaration"))
|
||||
return(result);
|
||||
|
||||
String n0 = state->look_ahead(0);
|
||||
if(n0 == "O=")
|
||||
{
|
||||
result->type_name = "auto";
|
||||
result->assign.push_back(script_parse_expression(state, delim1, delim2));
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result->type_name = state->consume('I').substr(1);
|
||||
String n2 = state->look_ahead(0);
|
||||
if(n2 == delim1 || n2 == delim2)
|
||||
{
|
||||
state->consume();
|
||||
return(result);
|
||||
}
|
||||
else if(n2 == "O=")
|
||||
{
|
||||
state->expect("O=", "declaration");
|
||||
result->assign.push_back(script_parse_expression(state, delim1, delim2));
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->unexpected_token();
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
ASTNode* parse_single_token(ParserState* state)
|
||||
{
|
||||
ASTNode* result = new ASTNode('?');
|
||||
|
||||
String n = state->consume();
|
||||
if(n[0] == 'Q')
|
||||
{
|
||||
result->type = 'S';
|
||||
result->string_literal = n.substr(1);
|
||||
}
|
||||
else if(n[0] == 'N')
|
||||
{
|
||||
result->type = 'N';
|
||||
result->string_literal = n.substr(1);
|
||||
}
|
||||
else if(n[0] == 'I')
|
||||
{
|
||||
result->type = 'I';
|
||||
result->identifier = n.substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->unexpected_token(-1);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
ASTNode* script_parse_assignment(ParserState* state, String delim1, String delim2)
|
||||
{
|
||||
ASTNode* result = new ASTNode('A');
|
||||
result->identifier = state->consume('I').substr(1);
|
||||
state->expect("O=", "assignment");
|
||||
result->assign.push_back(script_parse_expression(state, delim1, delim2));
|
||||
return(result);
|
||||
}
|
||||
|
||||
ASTNode* script_parse_expression(ParserState* state, String delim1, String delim2)
|
||||
{
|
||||
ASTNode* result = new ASTNode('E');
|
||||
|
||||
String n = state->look_ahead(0);
|
||||
|
||||
if(n == "O(")
|
||||
{
|
||||
state->consume();
|
||||
result->children.push_back(script_parse_expression(state, "O)", ""));
|
||||
}
|
||||
else if(n == delim1 || n == delim2)
|
||||
{
|
||||
state->consume();
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
String n2 = state->look_ahead(1);
|
||||
if(n[0] == 'I' && n2 == "O:")
|
||||
{
|
||||
return(script_parse_declaration(state, "O;", ""));
|
||||
}
|
||||
else if(n2 == delim1 || n2 == delim2)
|
||||
{
|
||||
// single component 'expression'
|
||||
result = parse_single_token(state);
|
||||
state->consume();
|
||||
return(result);
|
||||
}
|
||||
else if(n[0] == 'I' && n2 == "O=")
|
||||
{
|
||||
result = script_parse_assignment(state, delim1, delim2);
|
||||
n2 = state->look_ahead(0);
|
||||
if(n2 != delim1 && n2 != delim2)
|
||||
case(TT_INT):
|
||||
{
|
||||
state->unexpected_token();
|
||||
if(isdigit(c))
|
||||
ctok->literal += c;
|
||||
else if(c == '.')
|
||||
{
|
||||
ctok->type = TT_FLOAT;
|
||||
ctok->literal += c;
|
||||
}
|
||||
else
|
||||
NEW_TOKEN
|
||||
break;
|
||||
}
|
||||
case(TT_FLOAT):
|
||||
{
|
||||
if(isdigit(c))
|
||||
ctok->literal += c;
|
||||
else
|
||||
NEW_TOKEN
|
||||
break;
|
||||
}
|
||||
case(TT_OPERATOR):
|
||||
{
|
||||
ctok->literal += c;
|
||||
c = ' ';
|
||||
NEW_TOKEN
|
||||
break;
|
||||
}
|
||||
case(TT_STRING):
|
||||
{
|
||||
if(c == ctok->delim)
|
||||
{
|
||||
c = ' ';
|
||||
NEW_TOKEN
|
||||
}
|
||||
else
|
||||
ctok->literal += c;
|
||||
break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->unexpected_token();
|
||||
state->error += " in expression";
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back(ctok);
|
||||
return(result);
|
||||
}
|
||||
|
||||
ParserState* script_parse(StringList tokens)
|
||||
String to_string(std::vector<Token*> t)
|
||||
{
|
||||
ParserState* state = new ParserState();
|
||||
state->tokens = tokens;
|
||||
state->root = new ASTNode('M');
|
||||
|
||||
while(state->token_index < state->tokens.size())
|
||||
String result = "";
|
||||
for(auto& ti : t)
|
||||
{
|
||||
state->root->children.push_back(script_parse_expression(state, "O;", ""));
|
||||
result += concat(TokenTypeName[ti->type], "(", ti->literal, ") ");
|
||||
}
|
||||
|
||||
return(state);
|
||||
return(result);
|
||||
}
|
||||
// "
|
||||
|
||||
RENDER()
|
||||
{
|
||||
@@ -349,17 +131,9 @@ RENDER()
|
||||
</form>
|
||||
<pre><?
|
||||
|
||||
StringList tokens = script_tokenize(script_src);
|
||||
//print(var_dump(tokens));
|
||||
auto tokens = script_tokenize(script_src);
|
||||
print(html_escape(to_string(tokens)));
|
||||
|
||||
ParserState* ps = script_parse(tokens);
|
||||
|
||||
if(ps->error_location > 0)
|
||||
{
|
||||
print(ps->error, " @ token ", 1+ps->error_location, "\n");
|
||||
}
|
||||
|
||||
print(ps->root->to_string());
|
||||
|
||||
?></pre>
|
||||
Params
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
RENDER()
|
||||
{
|
||||
auto p = compiler_load_shared_unit(context, "post.uce");
|
||||
if(p)
|
||||
print(to_string(p));
|
||||
}
|
||||
+2
-2
@@ -34,11 +34,11 @@ RENDER()
|
||||
|
||||
<script>
|
||||
|
||||
setInterval(() => {
|
||||
/*setInterval(() => {
|
||||
|
||||
load(document.getElementById('task-status'), 'task-status.uce?task-name=<?= uri_encode(task_name) ?>');
|
||||
|
||||
}, 200);
|
||||
}, 200);*/
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
RENDER()
|
||||
{
|
||||
DTree t;
|
||||
|
||||
String task_name = first(context->get["task-name"], "example-task");
|
||||
|
||||
<>
|
||||
<link rel="stylesheet" href='style.css'></link>
|
||||
<h1>
|
||||
<a href="index.uce">UCE Test</a>:
|
||||
Task repeat
|
||||
</h1>
|
||||
|
||||
<script>
|
||||
|
||||
function load(target, url) {
|
||||
var r = new XMLHttpRequest();
|
||||
r.open("GET", url, true);
|
||||
r.onreadystatechange = function () {
|
||||
if (r.readyState != 4 || r.status != 200) return;
|
||||
target.innerHTML = r.responseText;
|
||||
};
|
||||
r.send();
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="?">
|
||||
Task name
|
||||
<input type="text" name="task-name" value="<?= task_name ?>"/>
|
||||
<input type="submit" name="cmd" value="Get Info"/>
|
||||
<input type="submit" name="cmd" value="Execute"/>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
|
||||
/*setInterval(() => {
|
||||
|
||||
load(document.getElementById('task-status'), 'task-status.uce?task-name=<?= uri_encode(task_name) ?>');
|
||||
|
||||
}, 200);*/
|
||||
|
||||
</script>
|
||||
|
||||
Task Status
|
||||
|
||||
<pre id="task-status" style="white-space: pre-wrap"><?
|
||||
|
||||
print("Task Name: ", task_name, "\n");
|
||||
print("Task ID: ", task_pid(task_name), "\n");
|
||||
print("Task Running: ", task_pid(task_name) == 0 ? "no" : "yes", "\n");
|
||||
|
||||
|
||||
?></pre>
|
||||
|
||||
<?
|
||||
if(context->get["cmd"] == "Execute")
|
||||
{
|
||||
?>
|
||||
Task Start
|
||||
|
||||
<pre style="white-space: pre-wrap"><?
|
||||
|
||||
print("New Task ID: ", task_repeat("example-task", 5, []() {
|
||||
|
||||
sleep(1);
|
||||
|
||||
}), "\n");
|
||||
|
||||
print("Task interval: 5 seconds");
|
||||
|
||||
?></pre><?
|
||||
}
|
||||
?>
|
||||
|
||||
Params
|
||||
<pre><?= var_dump(context->get) ?></pre>
|
||||
</>
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user