Merge pull request 'pass-test-tokenize-all' (#1) from pass-test-tokenize-all into main
Reviewed-on: #1
This commit is contained in:
		
						commit
						92c3e41810
					
				| @ -58,7 +58,8 @@ func (err Error) Error () (formattedMessage string) { | ||||
| 
 | ||||
| 		// print an arrow with a tail spanning the width of the mistake | ||||
| 		columnCountdown := err.Location.column | ||||
| 		for columnCountdown > 0 { | ||||
| 		for columnCountdown > 1 { | ||||
| 			// TODO: for tabs, print out a teb instead. | ||||
| 			formattedMessage += " " | ||||
| 			columnCountdown -- | ||||
| 		} | ||||
| @ -66,9 +67,9 @@ func (err Error) Error () (formattedMessage string) { | ||||
| 			// TODO: for tabs, print out 8 of these instead. | ||||
| 			formattedMessage += "-" | ||||
| 		} | ||||
| 		formattedMessage += "-\n" | ||||
| 		formattedMessage += "^\n" | ||||
| 	} | ||||
| 	formattedMessage += err.message + "-\n" | ||||
| 	formattedMessage += err.message + "\n" | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
|  | ||||
							
								
								
									
										203
									
								
								lexer/lexer.go
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								lexer/lexer.go
									
									
									
									
									
								
							| @ -1,7 +1,9 @@ | ||||
| package lexer | ||||
| 
 | ||||
| import "io" | ||||
| import "fmt" | ||||
| import "github.com/sashakoshka/arf/file" | ||||
| import "github.com/sashakoshka/arf/types" | ||||
| 
 | ||||
| // LexingOperation holds information about an ongoing lexing operataion. | ||||
| type LexingOperation struct { | ||||
| @ -31,22 +33,62 @@ func (lexer *LexingOperation) tokenize () (err error) { | ||||
| 	if err != nil { return } | ||||
| 
 | ||||
| 	for { | ||||
| 		fmt.Println(string(lexer.char)) | ||||
| 		 | ||||
| 		lowercase := lexer.char >= 'a' && lexer.char <= 'z' | ||||
| 		uppercase := lexer.char >= 'A' && lexer.char <= 'Z' | ||||
| 		number    := lexer.char >= '0' && lexer.char <= '9' | ||||
| 
 | ||||
| 		if number { | ||||
| 			// TODO: tokenize number begin | ||||
| 			err = lexer.tokenizeNumberBeginning(false) | ||||
| 			if err != nil { return } | ||||
| 		} else if lowercase || uppercase { | ||||
| 			// TODO: tokenize alpha begin | ||||
| 			err = lexer.tokenizeAlphaBeginning() | ||||
| 			if err != nil { return } | ||||
| 		} else { | ||||
| 			err = lexer.tokenizeSymbolBeginning() | ||||
| 			if err != nil { return err } | ||||
| 			if err != nil { return } | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO:  skip whitespace | ||||
| 		err = lexer.skipSpaces() | ||||
| 		if err != nil { return } | ||||
| 	} | ||||
| 
 | ||||
| 	if lexer.tokens[len(lexer.tokens) - 1].kind != TokenKindNewline { | ||||
| 		lexer.addToken(Token { kind: TokenKindNewline }) | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (lexer *LexingOperation) tokenizeAlphaBeginning () (err error) { | ||||
| 	got := "" | ||||
| 
 | ||||
| 	for { | ||||
| 		lowercase := lexer.char >= 'a' && lexer.char <= 'z' | ||||
| 		uppercase := lexer.char >= 'A' && lexer.char <= 'Z' | ||||
| 		number    := lexer.char >= '0' && lexer.char <= '9' | ||||
| 		if !lowercase && !uppercase && !number { break } | ||||
| 
 | ||||
| 		got += string(lexer.char) | ||||
| 
 | ||||
| 		lexer.nextRune() | ||||
| 	} | ||||
| 
 | ||||
| 	token := Token { kind: TokenKindName, value: got } | ||||
| 
 | ||||
| 	if len(got) == 2 { | ||||
| 		firstValid  := got[0] == 'n' || got[0] == 'r' || got[0] == 'w' | ||||
| 		secondValid := got[1] == 'n' || got[1] == 'r' || got[1] == 'w' | ||||
| 
 | ||||
| 		if firstValid && secondValid { | ||||
| 			token.kind  = TokenKindPermission | ||||
| 			token.value = types.PermissionFrom(got) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	lexer.addToken(token) | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| @ -55,7 +97,8 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) { | ||||
| 	case '#': | ||||
| 		// comment | ||||
| 		for lexer.char != '\n' { | ||||
| 			lexer.nextRune() | ||||
| 			err = lexer.nextRune() | ||||
| 			if err != nil { return } | ||||
| 		} | ||||
| 	case '\t': | ||||
| 		// indent level | ||||
| @ -75,105 +118,146 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) { | ||||
| 			lexer.addToken (Token { | ||||
| 				kind: TokenKindIndent, | ||||
| 			}) | ||||
| 			lexer.nextRune() | ||||
| 			err = lexer.nextRune() | ||||
| 			if err != nil { return } | ||||
| 		} | ||||
| 	case '\n': | ||||
| 		// line break | ||||
| 		lastLineEmpty := true | ||||
| 		tokenIndex := len(lexer.tokens) - 1 | ||||
| 		for lexer.tokens[tokenIndex].kind != TokenKindNewline  { | ||||
| 			if lexer.tokens[tokenIndex].kind != TokenKindIndent { | ||||
| 
 | ||||
| 				lastLineEmpty = false | ||||
| 				break | ||||
| 			}	 | ||||
| 			tokenIndex -- | ||||
| 		} | ||||
| 
 | ||||
| 		if lastLineEmpty { | ||||
| 			lexer.tokens = lexer.tokens[:tokenIndex] | ||||
| 		} | ||||
| 		 | ||||
| 		// TODO: if last line was blank, (ony whitespace) discard. | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindNewline, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '"': | ||||
| 		// TODO: tokenize string literal | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.tokenizeString(false) | ||||
| 	case '\'': | ||||
| 		// TODO: tokenize rune literal | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.tokenizeString(true) | ||||
| 	case ':': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindColon, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '.': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindDot, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '[': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindLBracket, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case ']': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindRBracket, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '{': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindLBrace, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '}': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindRBrace, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '+': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindPlus, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 		token := Token { kind: TokenKindPlus } | ||||
| 		if lexer.char == '+' { | ||||
| 			token.kind = TokenKindIncrement | ||||
| 		} | ||||
| 		lexer.addToken(token) | ||||
| 		err = lexer.nextRune() | ||||
| 	case '-': | ||||
| 		// TODO: tokenize dash begin | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.tokenizeDashBeginning() | ||||
| 	case '*': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindAsterisk, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '/': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindSlash, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '@': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindAt, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '!': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindExclamation, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '%': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindPercent, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '~': | ||||
| 		lexer.addToken (Token { | ||||
| 			kind: TokenKindTilde, | ||||
| 		}) | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 	case '<': | ||||
| 		// TODO: tokenize less than begin | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 		token := Token { kind: TokenKindLessThan } | ||||
| 		if lexer.char == '<' { | ||||
| 			token.kind = TokenKindLShift | ||||
| 		} | ||||
| 		lexer.addToken(token) | ||||
| 		err = lexer.nextRune() | ||||
| 	case '>': | ||||
| 		// TODO: tokenize greater than begin | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 		token := Token { kind: TokenKindGreaterThan } | ||||
| 		if lexer.char == '>' { | ||||
| 			token.kind = TokenKindRShift | ||||
| 		} | ||||
| 		lexer.addToken(token) | ||||
| 		err = lexer.nextRune() | ||||
| 	case '|': | ||||
| 		// TODO: tokenize bar begin | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 		token := Token { kind: TokenKindBinaryOr } | ||||
| 		if lexer.char == '|' { | ||||
| 			token.kind = TokenKindLogicalOr | ||||
| 		} | ||||
| 		lexer.addToken(token) | ||||
| 		err = lexer.nextRune() | ||||
| 	case '&': | ||||
| 		// TODO: tokenize and begin | ||||
| 		lexer.nextRune() | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 		token := Token { kind: TokenKindBinaryAnd } | ||||
| 		if lexer.char == '&' { | ||||
| 			token.kind = TokenKindLogicalAnd | ||||
| 		} | ||||
| 		lexer.addToken(token) | ||||
| 		err = lexer.nextRune() | ||||
| 	default: | ||||
| 		err = file.NewError ( | ||||
| 			lexer.file.Location(), 1, | ||||
| 			"unexpected character " + | ||||
| 			"unexpected symbol character " + | ||||
| 			string(lexer.char), | ||||
| 			file.ErrorKindError) | ||||
| 		return | ||||
| @ -182,10 +266,53 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) { | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (lexer *LexingOperation) tokenizeDashBeginning () (err error) { | ||||
| 	err = lexer.nextRune() | ||||
| 	if err != nil { return } | ||||
| 
 | ||||
| 	if lexer.char == '-' { | ||||
| 		token := Token { kind: TokenKindDecrement } | ||||
| 
 | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 
 | ||||
| 		if lexer.char == '-' { | ||||
| 			token.kind = TokenKindSeparator | ||||
| 			lexer.nextRune() | ||||
| 		} | ||||
| 		lexer.addToken(token) | ||||
| 	} else if lexer.char == '>' { | ||||
| 		token := Token { kind: TokenKindReturnDirection } | ||||
| 
 | ||||
| 		err = lexer.nextRune()  | ||||
| 		if err != nil { return } | ||||
| 
 | ||||
| 		lexer.addToken(token) | ||||
| 	} else if lexer.char >= '0' && lexer.char <= '9' { | ||||
| 		lexer.tokenizeNumberBeginning(true) | ||||
| 	} else { | ||||
| 		token := Token { kind: TokenKindMinus } | ||||
| 		lexer.addToken(token) | ||||
| 	} | ||||
| 	 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // addToken adds a new token to the lexer's token slice. | ||||
| func (lexer *LexingOperation) addToken (token Token) { | ||||
| 	lexer.tokens = append(lexer.tokens, token) | ||||
| } | ||||
| 
 | ||||
| // skipSpaces skips all space characters (not tabs or newlines) | ||||
| func (lexer *LexingOperation) skipSpaces () (err error) { | ||||
| 	for lexer.char == ' ' { | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // nextRune advances the lexer to the next rune in the file. | ||||
| func (lexer *LexingOperation) nextRune () (err error) { | ||||
| 	lexer.char, _, err = lexer.file.ReadRune() | ||||
|  | ||||
| @ -13,10 +13,15 @@ func TestTokenizeAll (test *testing.T) { | ||||
| 	} | ||||
| 	 | ||||
| 	tokens, err := Tokenize(file) | ||||
| 	test.Log("resulting error:") | ||||
| 	test.Log(err.Error()) | ||||
| 	if err == nil { | ||||
| 		test.Log("Tokenize() should have returned an error") | ||||
| 
 | ||||
| 	// print all tokens | ||||
| 	for index, token := range tokens { | ||||
| 		test.Log(index, "\tgot token:", token.Describe()) | ||||
| 	} | ||||
| 	 | ||||
| 	if err != nil { | ||||
| 		test.Log("returned error:") | ||||
| 		test.Log(err.Error()) | ||||
| 		test.Fail() | ||||
| 		return | ||||
| 	} | ||||
| @ -28,10 +33,10 @@ func TestTokenizeAll (test *testing.T) { | ||||
| 			External: types.ModeWrite, | ||||
| 		}}, | ||||
| 		Token { kind: TokenKindReturnDirection }, | ||||
| 		Token { kind: TokenKindInt, value: -349820394 }, | ||||
| 		Token { kind: TokenKindUInt, value: 932748397 }, | ||||
| 		Token { kind: TokenKindInt, value: int64(-349820394) }, | ||||
| 		Token { kind: TokenKindUInt, value: uint64(932748397) }, | ||||
| 		Token { kind: TokenKindFloat, value: 239485.37520 }, | ||||
| 		Token { kind: TokenKindString, value: "hello world\n" }, | ||||
| 		Token { kind: TokenKindString, value: "hello world!\n" }, | ||||
| 		Token { kind: TokenKindRune, value: 'E' }, | ||||
| 		Token { kind: TokenKindName, value: "helloWorld" }, | ||||
| 		Token { kind: TokenKindColon }, | ||||
| @ -40,6 +45,7 @@ func TestTokenizeAll (test *testing.T) { | ||||
| 		Token { kind: TokenKindRBracket }, | ||||
| 		Token { kind: TokenKindLBrace }, | ||||
| 		Token { kind: TokenKindRBrace }, | ||||
| 		Token { kind: TokenKindNewline }, | ||||
| 		Token { kind: TokenKindPlus }, | ||||
| 		Token { kind: TokenKindMinus }, | ||||
| 		Token { kind: TokenKindIncrement }, | ||||
| @ -58,6 +64,7 @@ func TestTokenizeAll (test *testing.T) { | ||||
| 		Token { kind: TokenKindLogicalOr }, | ||||
| 		Token { kind: TokenKindBinaryAnd }, | ||||
| 		Token { kind: TokenKindLogicalAnd }, | ||||
| 		Token { kind: TokenKindNewline }, | ||||
| 	} | ||||
| 
 | ||||
| 	if len(tokens) != len(correct) { | ||||
| @ -70,6 +77,9 @@ func TestTokenizeAll (test *testing.T) { | ||||
| 	for index, token := range tokens { | ||||
| 		if !token.Equals(correct[index]) { | ||||
| 			test.Log("token", index, "not equal") | ||||
| 			test.Log ( | ||||
| 				"have", token.Describe(), | ||||
| 				"want", correct[index].Describe()) | ||||
| 			test.Fail() | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										124
									
								
								lexer/numbers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								lexer/numbers.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | ||||
| package lexer | ||||
| 
 | ||||
| import "github.com/sashakoshka/arf/file" | ||||
| 
 | ||||
| // tokenizeSymbolBeginning lexes a token that starts with a number. | ||||
| func (lexer *LexingOperation) tokenizeNumberBeginning (negative bool) (err error) { | ||||
| 	var number   uint64 | ||||
| 	var fragment float64 | ||||
| 	var isFloat  bool | ||||
| 
 | ||||
| 	if lexer.char == '0' { | ||||
| 		lexer.nextRune() | ||||
| 
 | ||||
| 		if lexer.char == 'x' { | ||||
| 			lexer.nextRune() | ||||
| 			number, fragment, isFloat, err = lexer.tokenizeNumber(16) | ||||
| 		} else if lexer.char == 'b' { | ||||
| 			lexer.nextRune() | ||||
| 			number, fragment, isFloat, err = lexer.tokenizeNumber(2) | ||||
| 		} else if lexer.char == '.' { | ||||
| 			number, fragment, isFloat, err = lexer.tokenizeNumber(10) | ||||
| 		} else if lexer.char >= '0' && lexer.char <= '9' { | ||||
| 			number, fragment, isFloat, err = lexer.tokenizeNumber(8) | ||||
| 		} else { | ||||
| 			return file.NewError ( | ||||
| 				lexer.file.Location(), 1, | ||||
| 				"unexpected character in number literal", | ||||
| 				file.ErrorKindError) | ||||
| 		} | ||||
| 	} else { | ||||
| 		number, fragment, isFloat, err = lexer.tokenizeNumber(10) | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { return } | ||||
| 
 | ||||
| 	token := Token { } | ||||
| 
 | ||||
| 	if isFloat { | ||||
| 		floatNumber := float64(number) + fragment | ||||
| 	 | ||||
| 		token.kind  = TokenKindFloat | ||||
| 		if negative { | ||||
| 			token.value = floatNumber * -1 | ||||
| 		} else { | ||||
| 			token.value = floatNumber | ||||
| 		} | ||||
| 	} else { | ||||
| 		if negative { | ||||
| 			token.kind  = TokenKindInt | ||||
| 			token.value = int64(number) * -1 | ||||
| 		} else { | ||||
| 			token.kind  = TokenKindUInt | ||||
| 			token.value = uint64(number) | ||||
| 		}		 | ||||
| 	} | ||||
| 	 | ||||
| 	lexer.addToken(token) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // runeToDigit converts a rune from 0-F to a corresponding digit, with a maximum | ||||
| // radix. If the character is invalid, or the digit is too big, it will return | ||||
| // false for worked. | ||||
| func runeToDigit (char rune, radix uint64) (digit uint64, worked bool) { | ||||
| 	worked = true | ||||
| 
 | ||||
| 	if char >= '0' && char <= '9' { | ||||
| 		digit = uint64(char - '0') | ||||
| 	} else if char >= 'A' && char <= 'F' { | ||||
| 		digit = uint64(char - 'A' + 9) | ||||
| 	} else if char >= 'a' && char <= 'f' { | ||||
| 		digit = uint64(char - 'a' + 9) | ||||
| 	} else { | ||||
| 		worked = false | ||||
| 	} | ||||
| 
 | ||||
| 	if digit >= radix { | ||||
| 		worked = false | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // tokenizeNumber reads and tokenizes a number with the specified radix. | ||||
| func (lexer *LexingOperation) tokenizeNumber ( | ||||
| 	radix uint64, | ||||
| ) ( | ||||
| 	number   uint64, | ||||
| 	fragment float64, | ||||
| 	isFloat  bool, | ||||
| 	err      error, | ||||
| ) { | ||||
| 	for { | ||||
| 		digit, worked := runeToDigit(lexer.char, radix) | ||||
| 		if !worked { break } | ||||
| 
 | ||||
| 		number *= radix | ||||
| 		number += digit | ||||
| 
 | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 	} | ||||
| 	 | ||||
| 	if lexer.char == '.' { | ||||
| 		isFloat = true | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 
 | ||||
| 		coef := 1 / float64(radix) | ||||
| 		for { | ||||
| 			digit, worked := runeToDigit(lexer.char, radix) | ||||
| 			if !worked { break } | ||||
| 
 | ||||
| 			fragment += float64(digit) * coef | ||||
| 			 | ||||
| 			coef /= float64(radix) | ||||
| 
 | ||||
| 			err = lexer.nextRune() | ||||
| 			if err != nil { return } | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										77
									
								
								lexer/text.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								lexer/text.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | ||||
| package lexer | ||||
| 
 | ||||
| import "github.com/sashakoshka/arf/file" | ||||
| 
 | ||||
| var escapeSequenceMap = map[rune] rune { | ||||
|         'a':  '\x07', | ||||
|         'b':  '\x08', | ||||
|         'f':  '\x0c', | ||||
|         'n':  '\x0a', | ||||
|         'r':  '\x0d', | ||||
|         't':  '\x09', | ||||
|         'v':  '\x0b', | ||||
|         '\'': '\'', | ||||
|         '"':  '"', | ||||
|         '\\': '\\', | ||||
| } | ||||
| 
 | ||||
| func (lexer *LexingOperation) tokenizeString (isRuneLiteral bool) (err error) { | ||||
| 	err = lexer.nextRune() | ||||
| 	if err != nil { return } | ||||
| 
 | ||||
| 	got := "" | ||||
| 
 | ||||
| 	for { | ||||
| 		// TODO: add hexadecimal escape codes | ||||
| 		if lexer.char == '\\' { | ||||
| 			err = lexer.nextRune() | ||||
| 			if err != nil { return } | ||||
| 	 | ||||
| 			actual, exists := escapeSequenceMap[lexer.char] | ||||
| 			if exists { | ||||
| 				got += string(actual) | ||||
| 			} else { | ||||
| 				err = file.NewError ( | ||||
| 					lexer.file.Location(), 1, | ||||
| 					"unknown escape character " + | ||||
| 					string(lexer.char), file.ErrorKindError) | ||||
| 				return | ||||
| 			} | ||||
| 		} else { | ||||
| 			got += string(lexer.char) | ||||
| 		} | ||||
| 		 | ||||
| 		err = lexer.nextRune() | ||||
| 		if err != nil { return } | ||||
| 
 | ||||
| 		if isRuneLiteral { | ||||
| 			if lexer.char == '\'' { break } | ||||
| 		} else { | ||||
| 			if lexer.char == '"'  { break } | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	err = lexer.nextRune() | ||||
| 	if err != nil { return } | ||||
| 
 | ||||
| 	token := Token { } | ||||
| 
 | ||||
| 	if isRuneLiteral { | ||||
| 		if len(got) > 1 { | ||||
| 			err = file.NewError ( | ||||
| 				lexer.file.Location(), len(got) - 1, | ||||
| 				"excess data in rune literal", | ||||
| 				file.ErrorKindError) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		token.kind  = TokenKindRune | ||||
| 		token.value = rune([]rune(got)[0]) | ||||
| 	} else { | ||||
| 		token.kind  = TokenKindString | ||||
| 		token.value = got | ||||
| 	} | ||||
| 
 | ||||
| 	lexer.addToken(token) | ||||
| 	return | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| package lexer | ||||
| 
 | ||||
| import "fmt" | ||||
| import "github.com/sashakoshka/arf/file" | ||||
| 
 | ||||
| // TokenKind is an enum represzenting what role a token has. | ||||
| @ -84,3 +85,86 @@ func (token Token) Equals (testToken Token) (match bool) { | ||||
| func (token Token) Location () (location file.Location) { | ||||
| 	return token.location | ||||
| } | ||||
| 
 | ||||
| // Describe generates a textual description of the token to be used in debug | ||||
| // logs. | ||||
| func (token Token) Describe () (description string) { | ||||
| 	switch token.kind { | ||||
| 	case TokenKindNewline: | ||||
| 		description += "Newline" | ||||
| 	case TokenKindIndent: | ||||
| 		description += "Indent" | ||||
| 	case TokenKindSeparator: | ||||
| 		description += "Separator" | ||||
| 	case TokenKindPermission: | ||||
| 		description += "Permission" | ||||
| 	case TokenKindReturnDirection: | ||||
| 		description += "ReturnDirection" | ||||
| 	case TokenKindInt: | ||||
| 		description += "Int" | ||||
| 	case TokenKindUInt: | ||||
| 		description += "UInt" | ||||
| 	case TokenKindFloat: | ||||
| 		description += "Float" | ||||
| 	case TokenKindString: | ||||
| 		description += "String" | ||||
| 	case TokenKindRune: | ||||
| 		description += "Rune" | ||||
| 	case TokenKindName: | ||||
| 		description += "Name" | ||||
| 	case TokenKindColon: | ||||
| 		description += "Colon" | ||||
| 	case TokenKindDot: | ||||
| 		description += "Dot" | ||||
| 	case TokenKindLBracket: | ||||
| 		description += "LBracket" | ||||
| 	case TokenKindRBracket: | ||||
| 		description += "RBracket" | ||||
| 	case TokenKindLBrace: | ||||
| 		description += "LBrace" | ||||
| 	case TokenKindRBrace: | ||||
| 		description += "RBrace" | ||||
| 	case TokenKindPlus: | ||||
| 		description += "Plus" | ||||
| 	case TokenKindMinus: | ||||
| 		description += "Minus" | ||||
| 	case TokenKindIncrement: | ||||
| 		description += "Increment" | ||||
| 	case TokenKindDecrement: | ||||
| 		description += "Decrement" | ||||
| 	case TokenKindAsterisk: | ||||
| 		description += "Asterisk" | ||||
| 	case TokenKindSlash: | ||||
| 		description += "Slash" | ||||
| 	case TokenKindAt: | ||||
| 		description += "At" | ||||
| 	case TokenKindExclamation: | ||||
| 		description += "Exclamation" | ||||
| 	case TokenKindPercent: | ||||
| 		description += "Percent" | ||||
| 	case TokenKindTilde: | ||||
| 		description += "Tilde" | ||||
| 	case TokenKindLessThan: | ||||
| 		description += "LessThan" | ||||
| 	case TokenKindLShift: | ||||
| 		description += "LShift" | ||||
| 	case TokenKindGreaterThan: | ||||
| 		description += "GreaterThan" | ||||
| 	case TokenKindRShift: | ||||
| 		description += "RShift" | ||||
| 	case TokenKindBinaryOr: | ||||
| 		description += "BinaryOr" | ||||
| 	case TokenKindLogicalOr: | ||||
| 		description += "LogicalOr" | ||||
| 	case TokenKindBinaryAnd: | ||||
| 		description += "BinaryAnd" | ||||
| 	case TokenKindLogicalAnd: | ||||
| 		description += "LogicalAnd" | ||||
| 	} | ||||
| 
 | ||||
| 	if token.value != nil { | ||||
| 		description += fmt.Sprint(": ", token.value) | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @ -3,12 +3,30 @@ package types | ||||
| type Mode int | ||||
| 
 | ||||
| const ( | ||||
| 	ModeRead = iota | ||||
| 	ModeNone = iota | ||||
| 	ModeRead | ||||
| 	ModeWrite | ||||
| 	ModeNone | ||||
| ) | ||||
| 
 | ||||
| type Permission struct { | ||||
| 	Internal Mode | ||||
| 	External Mode | ||||
| } | ||||
| 
 | ||||
| func ModeFrom (char rune) (mode Mode) { | ||||
| 	switch (char) { | ||||
| 	case 'n': mode = ModeNone | ||||
| 	case 'r': mode = ModeRead | ||||
| 	case 'w': mode = ModeWrite	 | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func PermissionFrom (data string) (permission Permission) { | ||||
| 	if len(data) != 2 { return } | ||||
| 
 | ||||
| 	permission.Internal = ModeFrom(rune(data[0])) | ||||
| 	permission.External = ModeFrom(rune(data[1])) | ||||
| 	return | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user