rewrite variable expansion, add initial support for ... command expansion.

This commit is contained in:
Kelvin Sherlock 2016-07-27 14:06:57 -04:00
parent 47af010ba5
commit fe76877693

View File

@ -3,132 +3,131 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include "mpw-shell.h" #include "mpw-shell.h"
#include "error.h"
%%{ %%{
machine line_parser;
machine expand;
alphtype unsigned char; alphtype unsigned char;
escape = 0xb6; action push { scratch.push_back(fc); }
ws = [ \t]; action vinit { /* vinit */ ev.clear(); xcs = fcurs; fnext vstring_state; }
nl = '\n'; action vpush { /* vpush */ ev.push_back(fc); }
action vfinish0 { /* vfinish0 */ fnext *xcs; }
action push_back { action vfinish1 {
line.push_back(fc); /* vfinish1 */
} fnext *xcs;
action push_back_escape { auto iter = env.find(ev);
line.push_back(escape); if (iter != env.end()) {
line.push_back(fc); const std::string &s = iter->second;
} scratch.append(s);
sstring =
['] $push_back
( (any-nl-[']) $push_back )*
['] $push_back
$err{
fprintf(stderr, "### MPW Shell - 's must occur in pairs.\n");
} }
; }
action vfinish2 {
# same quoting logic as ' string /* vfinish2 */
vstring = fnext *xcs;
'{' auto iter = env.find(ev);
( (any-nl-'}') ${var.push_back(fc); } )* if (iter != env.end()) {
'}' // quote special chars...
${ const std::string &s = iter->second;
if (!var.empty()) { for (auto c : s) {
if (c == '\'' || c == '"' ) scratch.push_back(escape);
// flag to pass through vs "" ? scratch.push_back(c);
auto iter = env.find(var);
if (iter == env.end()) {
if (env.passthrough()) {
line.push_back('{');
line.append(var);
line.push_back('}');
}
}
else {
line.append((std::string)iter->second);
}
} }
var.clear();
} }
$err{ }
fprintf(stderr, "### MPW Shell - {s must occur in pairs.\n");
} action einit{ /* einit */ ev.clear(); xcs = fcurs; fnext estring_state; }
; action epush{ /* epush */ ev.push_back(fc); }
action efinish1{
/* efinish1 */
fnext *xcs;
throw std::runtime_error("MPW Shell - `...` not yet supported.");
}
action efinish2{
/* efinish2 */
fnext *xcs;
throw std::runtime_error("MPW Shell - `...` not yet supported.");
}
action vstring_error{
throw vstring_error();
}
action estring_error{
throw estring_error();
}
# double-quoted string. escape = 0xb6;
# escape \n is ignored. others do nothing. char = any - escape - ['"{`];
dstring = escape_seq = escape any;
["] $push_back
( schar = [^'];
escape ( sstring = ['] schar** ['];
nl ${ /* esc newline */ }
|
(any-nl) $push_back_escape
)
|
vstring
|
(any-escape-nl-["{]) $push_back
)* ["] $push_back
$err{
fprintf(stderr, "### MPW Shell - \"s must occur in pairs.\n");
}
;
main := vchar = [^}] $vpush;
( vchar1 = [^{}] $vpush;
sstring
| vstring0 = '}' @vfinish0;
dstring vstring1 = vchar1 vchar** '}' @vfinish1;
| vstring2 = '{' vchar** '}}' @vfinish2;
vstring
| vstring_state := (vstring0 | vstring1 | vstring2) $err(vstring_error);
escape any $push_back_escape vstring = '{' $vinit;
|
(any-['"{]) $push_back echar = (escape_seq | any - escape - [`]) $epush;
)*
; estring1 = echar+ '`' @efinish1;
estring2 = '`' echar* '``' @efinish2;
estring_state := (estring1 | estring2) $err(estring_error);
estring = '`' $einit;
dchar = escape_seq $push | estring | vstring | (any - escape - [`{"]) $push;
dstring = ["] dchar** ["];
main := (
escape_seq $push
| sstring $push
| dstring
| vstring
| estring
| char $push
)**;
}%% }%%
namespace {
%% write data;
%% write data;
/*
* has to be done separately since you can do dumb stuff like:
* set q '"' ; echo {q} dsfsdf"
*/
std::string expand_vars(const std::string &s, const Environment &env) {
if (s.find('{') == s.npos) return s;
std::string var;
std::string line;
int cs;
const unsigned char *p = (const unsigned char *)s.data();
const unsigned char *pe = (const unsigned char *)s.data() + s.size();
const unsigned char *eof = pe;
%%write init;
%%write exec;
return line;
} }
std::string expand_vars(const std::string &s, const Environment &env) {
if (s.find_first_of("{`", 0, 2) == s.npos) return s;
int cs;
int xcs;
const unsigned char *p = (const unsigned char *)s.data();
const unsigned char *pe = p + s.size();
const unsigned char *eof = pe;
std::string scratch;
std::string ev;
scratch.reserve(s.size());
%% write init;
%% write exec;
return scratch;
}