config.bmx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. ' Copyright (c) 2013-2020 Bruce A Henderson
  2. '
  3. ' Based on the public domain Monkey "trans" by Mark Sibly
  4. '
  5. ' This software is provided 'as-is', without any express or implied
  6. ' warranty. In no event will the authors be held liable for any damages
  7. ' arising from the use of this software.
  8. '
  9. ' Permission is granted to anyone to use this software for any purpose,
  10. ' including commercial applications, and to alter it and redistribute it
  11. ' freely, subject to the following restrictions:
  12. '
  13. ' 1. The origin of this software must not be misrepresented; you must not
  14. ' claim that you wrote the original software. If you use this software
  15. ' in a product, an acknowledgment in the product documentation would be
  16. ' appreciated but is not required.
  17. '
  18. ' 2. Altered source versions must be plainly marked as such, and must not be
  19. ' misrepresented as being the original software.
  20. '
  21. ' 3. This notice may not be removed or altered from any source
  22. ' distribution.
  23. '
  24. SuperStrict
  25. Import BRL.LinkedList
  26. Import BRL.Map
  27. Import BRL.FileSystem
  28. Import Pub.zlib
  29. Import BRL.Math
  30. Import "options.bmx"
  31. Import "base.stringhelper.bmx"
  32. Import "base64.bmx"
  33. Import "enums.c"
  34. Import "hash.c"
  35. ' debugging help
  36. Const DEBUG:Int = False
  37. Const ABORT_ON_NULL:Int = True
  38. Const PROFILER:Int = False
  39. Const DEBUGSTOP_ON_ERROR:Int = False
  40. Const SHOW_INTERNALERR_LOCATION:Int = True
  41. Global ENV_LANG$
  42. Global _errInfo$
  43. Global _errStack:TList = New TList
  44. ' bytes offset to the first field
  45. Global OBJECT_BASE_OFFSET:Int = 8
  46. ' 4 bytes on 32-bit, 8 bytes on 64-bit
  47. Global POINTER_SIZE:Int = 4
  48. Global _symbols$[]=[ "..","[]",":*",":/",":+",":-",":|",":&",":~~",":shr",":shl",":sar",":mod"]
  49. Global _symbols_map$[]=[ "..","[]","*=","/=","+=","-=","|=","&=","^=",">>=", "<<=",">>=","%=" ]
  50. Function PushErr( errInfo$ )
  51. _errStack.AddLast _errInfo
  52. _errInfo=errInfo
  53. End Function
  54. Function PopErr()
  55. _errInfo=String(_errStack.RemoveLast())
  56. End Function
  57. Function Err( err$ )
  58. If DEBUGSTOP_ON_ERROR Then
  59. DebugStop ' useful for debugging!
  60. End If
  61. Throw "Compile Error: "+err + "~n" + _errInfo + "~n"
  62. End Function
  63. Function Warn( err$ )
  64. 'If DEBUGSTOP_ON_ERROR Then
  65. ' DebugStop ' useful for debugging!
  66. 'End If
  67. Print "Compile Warning: "+err + "~n" + _errInfo + "~n"
  68. End Function
  69. Function FormatError:String(path:String, line:Int, char:Int)
  70. Return "[" + path + ";" + line + ";" + char + "]"
  71. End Function
  72. Function InternalErr(errorLocation:String)
  73. If DEBUGSTOP_ON_ERROR Then
  74. DebugStop ' useful for debugging!
  75. End If
  76. Local locationMsg:String
  77. If SHOW_INTERNALERR_LOCATION And errorLocation Then locationMsg = " in " + errorLocation
  78. Throw "Compile Error: Internal Error" + locationMsg + ".~nPlease report the issue, with an example if possible, to https://github.com/bmx-ng/bcc/issues/new~n" + _errInfo + "~n"
  79. End Function
  80. Function IsSpace:Int( ch:Int )
  81. Return ch<=Asc(" ") Or ch=$A0 ' NO-BREAK SPACE (U+00A0)
  82. End Function
  83. Function IsDigit:Int( ch:Int )
  84. Return ch>=Asc("0") And ch<=Asc("9")
  85. End Function
  86. Function IsAlpha:Int( ch:Int )
  87. Return (ch>=Asc("A") And ch<=Asc("Z")) Or (ch>=Asc("a") And ch<=Asc("z"))
  88. End Function
  89. Function IsBinDigit:Int( ch:Int )
  90. Return ch=Asc("0") Or ch=Asc("1")
  91. End Function
  92. Function IsHexDigit:Int( ch:Int )
  93. Return IsDigit(ch) Or (ch>=Asc("A") And ch<=Asc("F")) Or (ch>=Asc("a") And ch<=Asc("f"))
  94. End Function
  95. Function Todo()
  96. Err "TODO!"
  97. End Function
  98. Function StringToLong:Long(value:String)
  99. Local Sign:Int = 1
  100. Local i:Int
  101. While i < value.length And (value[i] = Asc("+") Or value[i] = Asc("-"))
  102. If value[i] = Asc("-") Then
  103. Sign = -1
  104. End If
  105. i :+ 1
  106. Wend
  107. Local n:Long = 0
  108. While i < value.length
  109. Local c:Int = value[i]
  110. If Not IsDigit(c) Exit
  111. n = n * 10 + (c-Asc("0"))
  112. i :+ 1
  113. Wend
  114. Return n
  115. End Function
  116. Function IsStandardFunc:Int(func:String)
  117. func = func.ToLower()
  118. Global funcs:String = ";isalnum;isalpha;isascii;isblank;iscntrl;isdigit;isgraph;islower;isprint;ispunct;isspace;isupper;isxdigit;" + ..
  119. "strlen;_wgetenv;_wputenv;"
  120. Return funcs.Find(func) > 0
  121. End Function
  122. Function mapSymbol:String(sym:String)
  123. For Local i:Int = 0 Until _symbols.length
  124. If sym = _symbols[i] Then
  125. Return _symbols_map[i]
  126. End If
  127. Next
  128. Return sym
  129. End Function
  130. 'enquote depending on ENV_LANG
  131. '
  132. Function LangEnquote$( str$ )
  133. str=EscapeString(str)
  134. ' str=str.Replace( "~0","\0" ) 'Fix me?
  135. For Local i:Int=0 Until str.Length
  136. If str[i]>=32 And str[i]<128 Continue
  137. Local t$,n:Int=str[i]
  138. While n
  139. Local c:Int=(n&15)+48
  140. If c>=58 c:+97-58
  141. t=Chr( c )+t
  142. n=(n Shr 4) & $0fffffff
  143. Wend
  144. If Not t t="0"
  145. If ENV_LANG = "cpp" Then
  146. 'Case "cpp"
  147. t="~q~q\x"+t+"~q~q"
  148. Else
  149. t="\u"+("0000"+t)[-4..]
  150. End If
  151. str=str[..i]+t+str[i+1..]
  152. i:+t.Length-1
  153. Next
  154. str="~q"+str+"~q"
  155. If ENV_LANG="cpp" str="L"+str
  156. Return str
  157. End Function
  158. Function EscapeString$(str$)
  159. str=str.Replace( "\","\\" )
  160. str=str.Replace( "~q","\~q" )
  161. str=str.Replace( "~n","\n" )
  162. str=str.Replace( "~r","\r" )
  163. str=str.Replace( "~t","\t" )
  164. Return str
  165. End Function
  166. Function EscapeLines:String(str:String)
  167. str=str.Replace("~n", "Newline")
  168. Return str
  169. End Function
  170. Function BmxEnquote$( str$ )
  171. str=str.Replace( "~~","~~~~" )
  172. str=str.Replace( "~q","~~q" )
  173. str=str.Replace( "~n","~~n" )
  174. str=str.Replace( "~r","~~r" )
  175. str=str.Replace( "~t","~~t" )
  176. str=str.Replace( "~0","~~0" )
  177. str="~q"+str+"~q"
  178. Return str
  179. End Function
  180. Function BmxUnquote$( str$, unquoted:Int = False )
  181. Local length:Int
  182. Local i:Int
  183. If Not unquoted Then
  184. If str.length < 2 Or str[str.length - 1] <> Asc("~q") Then
  185. Err "Expecting expression but encountered malformed string literal"
  186. End If
  187. length = str.length - 1
  188. i = 1
  189. Else
  190. length = str.length
  191. End If
  192. Local sb:TStringBuffer = New TStringBuffer
  193. While i < length
  194. Local c:Int = str[i]
  195. i :+ 1
  196. If c <> Asc("~~") Then
  197. sb.AppendChar(c)
  198. Continue
  199. End If
  200. If i = length Err "Bad escape sequence in string"
  201. c = str[i]
  202. i :+ 1
  203. Select c
  204. Case Asc("~~")
  205. sb.AppendChar(c)
  206. Case Asc("0")
  207. sb.AppendChar(0)
  208. Case Asc("t")
  209. sb.AppendChar(Asc("~t"))
  210. Case Asc("r")
  211. sb.AppendChar(Asc("~r"))
  212. Case Asc("n")
  213. sb.AppendChar(Asc("~n"))
  214. Case Asc("q")
  215. sb.AppendChar(Asc("~q"))
  216. Case Asc("$") ' hex
  217. c = str[i]
  218. i :+ 1
  219. Local n:Int
  220. While True
  221. Local v:Int
  222. If c >= Asc("0") And c <= Asc("9") Then
  223. v = c-Asc("0")
  224. Else If c >= Asc("a") And c <= Asc("f") Then
  225. v = c-Asc("a")+10
  226. Else If c >= Asc("A") And c <= Asc("F") Then
  227. v = c-Asc("A")+10
  228. Else If c <> Asc("~~")
  229. Err "Bad escape sequence in string"
  230. Else
  231. Exit
  232. End If
  233. n = (n Shl 4) | (v & $f)
  234. If i = length Err "Bad escape sequence in string"
  235. c = str[i]
  236. i :+ 1
  237. Wend
  238. If c <> Asc("~~") Err "Bad escape sequence in string"
  239. sb.AppendChar(n)
  240. Case Asc("%") ' bin
  241. c = str[i]
  242. i :+ 1
  243. Local n:Int
  244. While c = Asc("1") Or c = Asc("0")
  245. n :Shl 1
  246. If c = Asc("1") Then
  247. n :| 1
  248. End If
  249. If i = length Err "Bad escape sequence in string"
  250. c = str[i]
  251. i :+ 1
  252. Wend
  253. If c <> Asc("~~") Err "Bad escape sequence in string"
  254. sb.AppendChar(n)
  255. Default
  256. If c >= Asc("1") And c <= Asc("9") Then
  257. Local n:Int
  258. While c >= Asc("0") And c <= Asc("9")
  259. n = n * 10 + (c-Asc("0"))
  260. If i = length Err "Bad escape sequence in string"
  261. c = str[i]
  262. i :+ 1
  263. Wend
  264. If c <> Asc("~~") Err "Bad escape sequence in string"
  265. sb.AppendChar(n)
  266. Else
  267. Err "Bad escape sequence in string"
  268. End If
  269. End Select
  270. Wend
  271. Return sb.ToString()
  272. End Function
  273. Function BmxProcessMultiString:String( str:String )
  274. Local valid:Int
  275. If str.length < 7 Then
  276. Err "Expecting expression but encountered malformed multiline string literal"
  277. End If
  278. For Local i:Int = 0 Until 3
  279. If str[i] <> Asc("~q") Or str[str.length -1 -i] <> Asc("~q") Then
  280. Err "Expecting expression but encountered malformed multiline string literal"
  281. End If
  282. Next
  283. str = str[3..str.length - 3]
  284. ' normalise line endings
  285. str = str.Replace("~r~n", "~n").Replace("~r", "~n")
  286. If str[0] <> Asc("~n") Then
  287. Err "Expecting EOL but encountered malformed multiline string literal"
  288. End If
  289. str = str[1..]
  290. Local LINES:String[] = str.Split("~n")
  291. Local lineCount:Int = LINES.length - 1
  292. Local last:String = LINES[lineCount]
  293. Local i:Int = last.length - 1
  294. While i >= 0
  295. If last[i] <> Asc(" ") And last[i] <> Asc("~t") Then
  296. Err "Expecting trailing whitespace"
  297. End If
  298. i :- 1
  299. Wend
  300. Local trailingIndent:String = last
  301. ' strip indent
  302. If trailingIndent Then
  303. For i = 0 Until lineCount
  304. Local line:String = LINES[i]
  305. If line.StartsWith(trailingIndent) Then
  306. line = line[trailingIndent.length..]
  307. LINES[i] = line
  308. End If
  309. Next
  310. End If
  311. ' right trim
  312. For i = 0 Until lineCount
  313. Local line:String = LINES[i]
  314. Local index:Int = line.length
  315. While index
  316. index :- 1
  317. If line[index] <> Asc(" ") And line[index] <> Asc("~t") Then
  318. Exit
  319. End If
  320. Wend
  321. If index < line.length - 1 Then
  322. line = line[..index + 1]
  323. LINES[i] = line
  324. End If
  325. Next
  326. Local sb:TStringBuffer = New TStringBuffer
  327. For i = 0 Until lineCount
  328. Local line:String = LINES[i]
  329. Local length:Int = line.length
  330. Local softWrap:Int
  331. If line And line[line.length-1] = Asc("\") Then
  332. softWrap = True
  333. length :- 1
  334. End If
  335. If line Then
  336. sb.Append(line[..length])
  337. End If
  338. If Not softWrap And i < lineCount - 1 Then
  339. sb.Append("~n")
  340. End If
  341. Next
  342. Return BmxUnquote(sb.ToString(), True)
  343. End Function
  344. Type TStack Extends TList
  345. Method Push(obj:Object)
  346. AddFirst(obj)
  347. End Method
  348. Method Length:Int()
  349. Return count()
  350. End Method
  351. Method Get:Object(index:Int)
  352. Return ValueAtIndex(index)
  353. End Method
  354. Method Pop:Object()
  355. Return RemoveFirst()
  356. End Method
  357. End Type
  358. Type TStringList Extends TList
  359. Method Join:String(s:String)
  360. Local arr:String[] = New String[count()]
  361. Local index:Int
  362. For Local t:String = EachIn Self
  363. arr[index] = t
  364. index :+ 1
  365. Next
  366. Return s.Join(arr)
  367. End Method
  368. End Type
  369. Type TKeyValue
  370. Field key:Object
  371. Field value:Object
  372. Method Create:TKeyValue(key:Object,value:Object)
  373. Self.key = key
  374. Self.value = value
  375. Return Self
  376. End Method
  377. Method Compare:Int(other:Object)
  378. If Not TKeyValue(other) Return 0
  379. Return key.Compare(TKeyValue(other).key)
  380. End Method
  381. End Type
  382. Type TUnorderedMap
  383. Field list:TList = New TList
  384. Field map:TMap = New TMap
  385. Field valuesList:TList = New TList
  386. Method Insert( key:Object,value:Object )
  387. list.AddLAst(New TKeyValue.Create(key, value))
  388. valuesList.AddLast(value)
  389. map.Insert(key, value)
  390. End Method
  391. Method Keys:TList()
  392. Local klist:TList = New TList
  393. For Local kv:TKeyValue = EachIn list
  394. klist.AddLast(kv.key)
  395. Next
  396. Return klist
  397. End Method
  398. Method Values:TList()
  399. 'Local vlist:TList = New TList
  400. 'For Local kv:TKeyValue = EachIn list
  401. ' vlist.AddLast(kv.value)
  402. 'Next
  403. Return valuesList
  404. End Method
  405. Method Contains:Int( key:Object )
  406. Return map.Contains(key)
  407. End Method
  408. Method ValueForKey:Object( key:Object )
  409. Return map.ValueForKey(key)
  410. End Method
  411. End Type
  412. Function MakeKeywords:String()
  413. Local keywords:String
  414. keywords :+ "import brl.classes~n"
  415. keywords :+ "Asc%(v$)=~qbrl_blitz_keywords_asc~q~n"
  416. keywords :+ "Chr$(v%)=~qbrl_blitz_keywords_chr~q~n"
  417. keywords :+ "Len%(v:Object)=~qbrl_blitz_keywords_len~q~n"
  418. keywords :+ "IncbinPtr@*(v$)=~qbbIncbinPtr~q~n"
  419. keywords :+ "IncbinLen%(v$)=~qbbIncbinLen~q~n"
  420. Return keywords
  421. End Function
  422. Function FilePath:String(path:String)
  423. Local baseDir:String = ExtractDir(path)
  424. Local bmxDir:String = baseDir + "/.bmx"
  425. If FileType(bmxDir) <> FILETYPE_DIR Then
  426. Throw "Missing : " + bmxDir
  427. End If
  428. Return bmxDir
  429. End Function
  430. Function BuildHeaderName:String(path:String)
  431. If opt_buildtype = BUILDTYPE_MODULE Then
  432. path = opt_modulename + "_" + StripDir(path)
  433. Else
  434. Local dir:String = ExtractDir(path).ToLower().Replace("/.bmx","")
  435. dir = dir[dir.findLast("/") + 1..]
  436. If dir.EndsWith(".mod") Then
  437. dir = dir.Replace(".mod", "")
  438. End If
  439. Local file:String = StripDir(path).ToLower()
  440. path = dir + "_" + file
  441. End If
  442. Return TStringHelper.Sanitize(path, , True)
  443. End Function
  444. Rem
  445. bbdoc: Get the header file name from a given module ident, optionally with include path.
  446. End Rem
  447. Function ModuleHeaderFromIdent:String(ident:String, includePath:Int = False)
  448. Local ns:String = ident[..ident.find(".")]
  449. Local name:String = ident[ident.find(".") + 1..]
  450. Local file:String = name + ".bmx" + FileMung() + ".h"
  451. If includePath Then
  452. file = ns + ".mod/" + name + ".mod/.bmx/" + file
  453. End If
  454. Return file
  455. End Function
  456. Function HeaderFile:String(path:String, mung:String)
  457. Local fileDir:String = FilePath(path)
  458. Local file:String = StripDir(path)
  459. Return fileDir + "/" + file + mung + ".h"
  460. End Function
  461. Function OutputFilePath:String(path:String, mung:String, suffix:String, bmxDir:Int = False)
  462. Local fileDir:String = FilePath(path)
  463. If bmxDir Then
  464. fileDir :+ "/.bmx"
  465. End If
  466. Local file:String = StripDir(path)
  467. Return fileDir + "/" + file + mung + "." + suffix
  468. End Function
  469. Function FileMung:String(makeApp:Int = False)
  470. Local m:String = "."
  471. If makeApp Then
  472. Select opt_apptype
  473. Case APPTYPE_CONSOLE
  474. m :+ "console."
  475. Case APPTYPE_GUI
  476. m :+ "gui."
  477. End Select
  478. End If
  479. If opt_release Then
  480. m :+ "release"
  481. Else
  482. m :+ "debug"
  483. End If
  484. ' If opt_threaded Then
  485. ' m :+ ".mt"
  486. ' End If
  487. m :+ "." + opt_platform
  488. m :+ "." + opt_arch
  489. Return m
  490. End Function
  491. Function HeaderComment:String()
  492. ' TODO
  493. End Function
  494. Global fileRegister:TMap = New TMap
  495. Function GenHash:String(file:String)
  496. Local Hash:String = bmx_gen_hash(file)
  497. If Not fileRegister.Contains(Hash) Then
  498. fileRegister.Insert(Hash, file)
  499. End If
  500. Return Hash
  501. End Function
  502. Type TTemplateRecord
  503. Field start:Int
  504. Field file:String
  505. Field source:String
  506. Method Create:TTemplateRecord(start:Int, file:String, source:String)
  507. Self.start = start
  508. Self.file = file
  509. Self.source = source
  510. Return Self
  511. End Method
  512. Method ToString:String()
  513. Local s:Byte Ptr = source.ToUTF8String()
  514. ?Not bmxng
  515. Local slen:Int = strlen_(s)
  516. ?bmxng
  517. Local slen:UInt = strlen_(s)
  518. ?
  519. ?Not bmxng
  520. Local dlen:Int = slen + 12
  521. ?bmxng And (win32 Or ptr32)
  522. Local dlen:UInt = slen + 12
  523. ?bmxng And ptr64 And Not win32
  524. Local dlen:ULong = slen + 12
  525. ?
  526. Local data:Byte[dlen]
  527. compress2(data, dlen, s, slen, 9)
  528. MemFree(s)
  529. Local t:String = "{" + start +","+ slen +","+ LangEnquote(file) + ","
  530. t :+ LangEnquote(TBase64.Encode(data, Int(dlen), 0, TBase64.DONT_BREAK_LINES))
  531. Return t + "}"
  532. End Method
  533. Function Load:TTemplateRecord(start:Int, file:String, size:Int, source:String)
  534. ?Not bmxng
  535. Local dlen:Int = size + 1
  536. ?bmxng And (win32 Or ptr32)
  537. Local dlen:UInt = size + 1
  538. ?bmxng And ptr64 And Not win32
  539. Local dlen:ULong = size + 1
  540. ?
  541. Local data:Byte[dlen]
  542. Local s:Byte[] = TBase64.Decode(source)
  543. ?Not bmxng
  544. uncompress(data, dlen, s, s.length)
  545. ?bmxng
  546. uncompress(data, dlen, s, UInt(s.length))
  547. ?
  548. Return New TTemplateRecord.Create(start, file, String.FromUTF8String(data))
  549. End Function
  550. End Type
  551. Type TCallback
  552. Method Callback(obj:Object) Abstract
  553. End Type
  554. Extern
  555. Function strlen_:Int(s:Byte Ptr)="strlen"
  556. Function bmx_enum_next_power(char:Int, val:Long Var, ret:Long Var)
  557. Function bmx_gen_hash:String(txt:String)
  558. End Extern