Browse Source

String formatting.

Brucey 5 years ago
parent
commit
1fcaee8868
4 changed files with 146 additions and 14 deletions
  1. 98 6
      config.bmx
  2. 1 1
      options.bmx
  3. 5 0
      parser.bmx
  4. 42 7
      toker.bmx

+ 98 - 6
config.bmx

@@ -208,13 +208,21 @@ Function BmxEnquote$( str$ )
 	Return str
 End Function
 
-Function BmxUnquote$( str$ )
-	If str.length = 1 Or str[str.length - 1] <> Asc("~q") Then
-		Err "Expecting expression but encountered malformed string literal"
+Function BmxUnquote$( str$, unquoted:Int = False )
+	Local length:Int
+	Local i:Int
+	If Not unquoted Then
+		If str.length < 2 Or str[str.length - 1] <> Asc("~q") Then
+			Err "Expecting expression but encountered malformed string literal"
+		End If
+		length = str.length - 1
+		i = 1
+	Else
+		length = str.length
 	End If
-	Local length:Int = str.length - 1
+
 	Local sb:TStringBuffer = New TStringBuffer
-	Local i:Int = 1
+
 	While i < length
 		Local c:Int = str[i]
 		i :+ 1
@@ -299,6 +307,90 @@ Function BmxUnquote$( str$ )
 	Return sb.ToString()
 End Function
 
+Function BmxProcessMultiString:String( str:String )
+	Local valid:Int
+	If str.length < 7 Then
+		Err "Expecting expression but encountered malformed multiline string literal"
+	End If
+	
+	For Local i:Int = 0 Until 3
+		If str[i] <> Asc("~q") Or str[str.length -1 -i] <> Asc("~q") Then
+			Err "Expecting expression but encountered malformed multiline string literal"
+		End If
+	Next
+	
+	str = str[3..str.length - 3]
+	' normalise line endings
+	str = str.Replace("~r~n", "~n").Replace("~r", "~n")
+
+	If str[0] <> Asc("~n") Then
+		Err "Expecting EOL but encountered malformed multiline string literal"
+	End If
+
+	str = str[1..]
+
+	Local LINES:String[] = str.Split("~n")
+
+	Local lineCount:Int = LINES.length - 1
+	Local last:String = LINES[lineCount]
+	
+	Local i:Int = last.length - 1
+	While i >= 0
+		If last[i] <> Asc(" ") And last[i] <> Asc("~t") Then
+			Err "Expecting trailing whitespace"
+		End If
+		i :- 1
+	Wend
+	
+	Local trailingIndent:String = last
+	
+	' strip indent
+	If trailingIndent Then
+		For i = 0 Until lineCount
+			Local line:String = LINES[i]
+			If line.StartsWith(trailingIndent) Then
+				line = line[trailingIndent.length..]
+				LINES[i] = line
+			End If
+		Next
+	End If
+
+	' right trim
+	For i = 0 Until lineCount
+		Local line:String = LINES[i]
+		Local index:Int = line.length
+		While index
+			index :- 1
+			If line[index] <> Asc(" ") And line[index] <> Asc("~t") Then
+				Exit
+			End If
+		Wend
+		If index < line.length - 1 Then
+			line = line[..index + 1]
+			LINES[i] = line
+		End If
+	Next
+
+	Local sb:TStringBuffer = New TStringBuffer
+	For i = 0 Until lineCount
+		Local line:String = LINES[i]
+		Local length:Int = line.length
+		Local softWrap:Int
+		If line And line[line.length-1] = Asc("\") Then
+			softWrap = True
+			length :- 1
+		End If
+		If line Then
+			sb.Append(line[..length])
+		End If
+		If Not softWrap And i < lineCount - 1 Then
+			sb.Append("~n")
+		End If
+	Next
+
+	Return BmxUnquote(sb.ToString(), True)
+End Function
+
 Type TStack Extends TList
 
 	Method Push(obj:Object)
@@ -497,7 +589,7 @@ Global fileRegister:TMap = New TMap
 
 Function GenHash:String(file:String)
 	Local Hash:String = bmx_gen_hash(file)
-	
+
 	If Not fileRegister.Contains(Hash) Then
 		fileRegister.Insert(Hash, file)
 	End If

+ 1 - 1
options.bmx

@@ -25,7 +25,7 @@ SuperStrict
 
 Import "base.configmap.bmx"
 
-Const version:String = "0.121"
+Const version:String = "0.122"
 
 Const BUILDTYPE_APP:Int = 0
 Const BUILDTYPE_MODULE:Int = 1

+ 5 - 0
parser.bmx

@@ -1444,6 +1444,11 @@ Type TParser Extends TGenProcessor
 				expr=New TConstExpr.Create( TType.stringType,s )
 				_app.mapStringConsts(s)
 				NextToke
+			Case TOKE_STRINGMULTI
+				Local s:String = BmxProcessMultiString( _toke )
+				expr=New TConstExpr.Create( TType.stringType,s )
+				_app.mapStringConsts(s)
+				NextToke
 			Default
 				Err "Expecting expression but encountered "+DescribeToke(_toke)
 			End Select

+ 42 - 7
toker.bmx

@@ -39,6 +39,7 @@ Const TOKE_SYMBOL:Int=8
 Const TOKE_LINECOMMENT:Int=9
 Const TOKE_LONGLIT:Int=10
 Const TOKE_NATIVE:Int=11
+Const TOKE_STRINGMULTI:Int=12
 
 '***** Tokenizer *****
 Type TToker
@@ -199,17 +200,51 @@ Type TToker
 				_tokePos:+1
 			Wend
 		Else If str="~q"
+			Local isMulti:Int
 			_tokeType=TOKE_STRINGLIT
 			Local _tstr:String = TSTR()
-			While _tstr And _tstr<>"~q"
-				' Strings can't cross line boundries
-				If _tstr="~n" Then
+			If _tstr = "~q" Then
+				_tokePos:+1
+				Local _tstr2:String = TSTR()
+				If _tstr2 = "~q" Then
+					isMulti = True
+				Else
 					_tokePos:-1
-					Exit
 				End If
-				_tokePos:+1
-				_tstr = TSTR()
-			Wend
+			End If
+			If Not isMulti Then
+				While _tstr And _tstr<>"~q"
+					' Strings can't cross line boundries
+					If _tstr="~n" Then
+						_tokePos:-1
+						Exit
+					End If
+					_tokePos:+1
+					_tstr = TSTR()
+				Wend
+			Else
+				Local lineCount:Int
+				Local count:Int
+				_tokeType = TOKE_STRINGMULTI
+				While _tstr
+					_tokePos:+1
+					_tstr = TSTR()
+					
+					If _tstr = "~n" Then
+						lineCount:+1
+					End If
+					
+					If _tstr = "~q" Then
+						count :+ 1
+						If count = 3 Then
+							_line :+ lineCount - 1
+							Exit
+						End If
+					Else
+						count = 0
+					End If
+				Wend
+			End If
 			If _tokePos<_source.Length _tokePos:+1 Else _tokeType=TOKE_STRINGLITEX
 		Else If str="'"
 			Local _tstr:String = TSTR()