8888
8989--============================================================]]
9090
91- local VERSION = " 1.4 .0"
91+ local VERSION = " 1.5 .0"
9292
9393local KEYWORDS = {
9494 " and" ," break" ," do" ," else" ," elseif" ," end" ," false" ," for" ," function" ," if" ," in" ,
@@ -158,6 +158,7 @@ local errorIfNotRunningMeta
158158local escapePattern
159159local F
160160local getFileContents , fileExists
161+ local getNextUsableToken
161162local isAny
162163local loadLuaString , loadLuaFile
163164local maybeOutputLineNumber
@@ -505,7 +506,7 @@ function assertarg(n, v, ...)
505506 if vType == select (i , ... ) then return end
506507 end
507508
508- local fName = debug .getInfo (2 , " n" ).name
509+ local fName = debug.getinfo (2 , " n" ).name
509510 local expects = table.concat ({... }, " or " )
510511
511512 if fName == " " then fName = " ?" end
@@ -728,6 +729,16 @@ else
728729 end
729730end
730731
732+ -- token, index = getNextUsableToken( tokens, startIndex [, maxIndex=#tokens ] )
733+ function getNextUsableToken (tokens , i , iEnd )
734+ for i = i , math.min ((iEnd or math.huge ), # tokens ) do
735+ if not isAny (tokens [i ].type , " whitespace" ," comment" ) then
736+ return tokens [i ], i
737+ end
738+ end
739+ return nil
740+ end
741+
731742-- ==============================================================
732743-- = Preprocessor Functions =====================================
733744-- ==============================================================
@@ -1062,22 +1073,16 @@ local function _processFileOrString(params, isFile)
10621073 end
10631074 end
10641075
1065- -- local startOfLine = true
1066- local isMeta = false
1067- local isDual = false
1068- local metaStartLine = 0
1069- local bracketBalance = 0
1070-
10711076 local tokensToProcess = {}
10721077 local metaParts = {}
10731078
10741079 local tokenIndex = 1
10751080 local ln = 0
10761081
1077- local function outputTokens ( tokens )
1078- if not tokens [1 ] then return end
1082+ local function flushTokensToProcess ( )
1083+ if not tokensToProcess [1 ] then return end
10791084
1080- local lua = concatTokens (tokens , ln , params .addLineNumbers )
1085+ local lua = concatTokens (tokensToProcess , ln , params .addLineNumbers )
10811086 local luaMeta
10821087
10831088 if isDebug then
@@ -1087,42 +1092,107 @@ local function _processFileOrString(params, isFile)
10871092 end
10881093
10891094 table.insert (metaParts , luaMeta )
1090- ln = tokens [# tokens ].line
1095+ ln = tokensToProcess [# tokensToProcess ].line
1096+
1097+ tokensToProcess = {}
10911098 end
10921099
1093- while true do
1094- local tok = tokens [tokenIndex ]
1095- if not tok then break end
1100+ local function outputFinalDualValueStatement (metaLineStartIndex )
1101+ -- We expect the statement to look like any of these:
1102+ -- !!local x = ...
1103+ -- !!x = ...
1104+
1105+ -- Note: Something like the following produces a valid program, but won't work as expected:
1106+ -- !!local x = 1; local y = 2;
1107+ -- Only x will be outputted. @Robustness: Don't allow this.
1108+
1109+ local tok , i = getNextUsableToken (tokens , metaLineStartIndex , tokenIndex - 1 )
1110+ if not tok then
1111+ errorInFile (
1112+ luaUnprocessed , pathIn , tokens [metaLineStartIndex ].position , " Parser" ,
1113+ " Unexpected end of preprocessor line."
1114+ )
1115+ end
10961116
1097- local tokType = tok .type
1117+ local isLocal = (tok .type == " keyword" and tok .value == " local" )
1118+
1119+ if isLocal then
1120+ tok , i = getNextUsableToken (tokens , i + 1 , tokenIndex - 1 )
1121+ if not tok then
1122+ errorInFile (
1123+ luaUnprocessed , pathIn , tokens [metaLineStartIndex ].position , " Parser" ,
1124+ " Unexpected end of preprocessor line."
1125+ )
1126+ end
1127+ end
1128+
1129+ if tok .type ~= " identifier" then
1130+ errorInFile (
1131+ luaUnprocessed , pathIn , tok .position , " Parser" ,
1132+ " Expected an identifier."
1133+ )
1134+ end
1135+
1136+ local ident = tok .value
1137+
1138+ tok , i = getNextUsableToken (tokens , i + 1 , tokenIndex - 1 )
1139+ if not tok then
1140+ errorInFile (
1141+ luaUnprocessed , pathIn , tokens [metaLineStartIndex ].position , " Parser" ,
1142+ " Unexpected end of preprocessor line."
1143+ )
1144+ elseif not (tok .type == " punctuation" and tok .value == " =" ) then
1145+ errorInFile (
1146+ luaUnprocessed , pathIn , tok .position , " Parser" ,
1147+ " Preprocessor line must be an assignment."
1148+ )
1149+ end
1150+
1151+ if not getNextUsableToken (tokens , i + 1 , tokenIndex - 1 ) then
1152+ errorInFile (
1153+ luaUnprocessed , pathIn , tok .position , " Parser" ,
1154+ " Unexpected end of preprocessor line."
1155+ )
1156+ end
1157+
1158+ table.insert (metaParts , ' __LUA"' )
1159+ if isLocal then table.insert (metaParts , ' local ' ) end
1160+ table.insert (metaParts , ident )
1161+ table.insert (metaParts , ' = "__VAL(' )
1162+ table.insert (metaParts , ident )
1163+ table.insert (metaParts , ' )__LUA"\\ n"\n ' )
1164+
1165+ flushTokensToProcess ()
1166+ end
1167+
1168+ -- Note: Can be multiple lines if extended.
1169+ local function processMetaLine (isDual , metaStartLine )
1170+ local metaLineStartIndex = tokenIndex
1171+ local bracketBalance = 0
1172+
1173+ while true do
1174+ local tok = tokens [tokenIndex ]
1175+ if not tok then break end
1176+
1177+ local tokType = tok .type
10981178
1099- -- Meta line (or lines if extended).
1100- ---- ----------------------------
1101- if isMeta then
11021179 if
1103- (
1104- (tokType == " whitespace" and tok .value :find (" \n " , 1 , true ))
1105- or (tokType == " comment" and not tok .long )
1180+ bracketBalance == 0 and (
1181+ (tokType == " whitespace" and tok .value :find (" \n " , 1 , true )) or
1182+ (tokType == " comment" and not tok .long )
11061183 )
1107- and bracketBalance == 0
11081184 then
11091185 if tokType == " comment" then
11101186 table.insert (metaParts , tok .representation )
1111- if isDual then table.insert (tokensToProcess , tok ) end
11121187 else
11131188 table.insert (metaParts , " \n " )
1114- if isDual then table.insert (tokensToProcess , {type = " whitespace" , value = " \n " , representation = " \n " }) end
11151189 end
11161190
11171191 if isDual then
1118- outputTokens (tokensToProcess )
1119- tokensToProcess = {}
1192+ outputFinalDualValueStatement (metaLineStartIndex )
11201193 end
11211194
1122- -- startOfLine = true
1123- isMeta = false
1124- isDual = false
1125- bracketBalance = 0
1195+ break
11261196
11271197 elseif tokType == " pp_entry" then
11281198 errorInFile (
@@ -1134,9 +1204,6 @@ local function _processFileOrString(params, isFile)
11341204
11351205 else
11361206 table.insert (metaParts , tok .representation )
1137- if isDual then
1138- table.insert (tokensToProcess , tok )
1139- end
11401207
11411208 if tokType == " punctuation" and isAny (tok .value , " (" ," {" ," [" ) then
11421209 bracketBalance = bracketBalance + 1
@@ -1155,14 +1222,24 @@ local function _processFileOrString(params, isFile)
11551222 end
11561223 end
11571224
1225+ tokenIndex = tokenIndex + 1
1226+ end
1227+ end
1228+
1229+ while true do
1230+ local tok = tokens [tokenIndex ]
1231+ if not tok then break end
1232+
1233+ local tokType = tok .type
1234+
11581235 -- Meta block or start of meta line.
11591236 ---- ----------------------------
11601237
11611238 -- Meta block. Examples:
11621239 -- !( function sum(a, b) return a+b; end )
11631240 -- local text = !("Hello, mr. "..getName())
11641241 -- _G.!!("myRandomGlobal"..math.random(5)) = 99
1165- elseif
1242+ if
11661243 tokType == " pp_entry"
11671244 and tokens [tokenIndex + 1 ]
11681245 and tokens [tokenIndex + 1 ].type == " punctuation"
@@ -1174,10 +1251,7 @@ local function _processFileOrString(params, isFile)
11741251 local doOutputLua = tok .double
11751252 tokenIndex = tokenIndex + 2 -- Jump past "!(" or "!!(".
11761253
1177- if tokensToProcess [1 ] then
1178- outputTokens (tokensToProcess )
1179- tokensToProcess = {}
1180- end
1254+ flushTokensToProcess ()
11811255
11821256 local tokensInBlock = {}
11831257 local depth = 1
@@ -1244,48 +1318,22 @@ local function _processFileOrString(params, isFile)
12441318 -- local bar = foo..!(foo)
12451319 --
12461320 elseif tokType == " pp_entry" then
1247- -- elseif startOfLine and tokType == "pp_entry" then
1248- isMeta = true
1249- isDual = tok .double
1250- metaStartLine = tok .line
1251-
1252- if tokensToProcess [1 ] then
1253- outputTokens (tokensToProcess )
1254- tokensToProcess = {}
1255- end
1321+ flushTokensToProcess ()
12561322
1257- elseif tokType == " pp_entry" then
1258- if tok .double then
1259- errorInFile (luaUnprocessed , pathIn , tok .position , " Parser" , " Unexpected double preprocessor token." )
1260- else
1261- errorInFile (luaUnprocessed , pathIn , tok .position , " Parser" , " Unexpected preprocessor token." )
1262- end
1323+ tokenIndex = tokenIndex + 1
1324+ processMetaLine (tok .double , tok .line )
12631325
12641326 -- Non-meta.
12651327 ---- ----------------------------
1266-
1267- --[[ Potential start of meta line. (Must be at the start of the line, possibly after whitespace.) UPDATE: No longer true.
1268- elseif tokType == "whitespace" or (tokType == "comment" and not tok.long) then
1269- table.insert(tokensToProcess, tok)
1270-
1271- if not (tokType == "whitespace" and not tok.value:find("\n", 1, true)) then
1272- startOfLine = true
1273- end
1274- --]]
1275-
12761328 else
12771329 table.insert (tokensToProcess , tok )
1278- -- startOfLine = false
12791330 end
12801331 ---- ----------------------------
12811332
12821333 tokenIndex = tokenIndex + 1
12831334 end
12841335
1285- if tokensToProcess [1 ] then
1286- outputTokens (tokensToProcess )
1287- tokensToProcess = {}
1288- end
1336+ flushTokensToProcess ()
12891337
12901338 -- Run metaprogram.
12911339 -- ==============================================================
0 commit comments