コード例 #1
0
ファイル: lexer.go プロジェクト: danwakefield/gosh
func (l *Lexer) VariableSimple() {
	// When we enter this state we know we have at least one readable
	// char for the varname. That means that any character not valid
	// just terminates the parsing and we dont have to
	// worry about the case of an empty varname
	l.buffer.WriteRune(SentinalSubstitution)
	sv := SubVariable{SubType: VarSubNormal}
	varbuf := bytes.Buffer{}

	c := l.nextChar()
	switch {
	case char.IsSpecial(c):
		varbuf.WriteRune(c)
	case char.IsDigit(c):
		// Positional argv
		for {
			varbuf.WriteRune(c)
			c = l.nextChar()
			if !char.IsDigit(c) {
				l.backup()
				break
			}
		}
	case char.IsFirstInVarName(c):
		for {
			varbuf.WriteRune(c)
			c = l.nextChar()
			if !char.IsInVarName(c) {
				l.backup()
				break
			}
		}
	default:
		l.backup()
	}

	sv.VarName = varbuf.String()
	l.subs = append(l.subs, sv)
	return
}
コード例 #2
0
ファイル: lexer.go プロジェクト: danwakefield/gosh
func (l *Lexer) Substitution() {
	// Upon entering we have only read the '$'
	// Perform the lex of a single complete substitution before returning
	// control to the calling location
	c := l.nextChar()

	switch {
	default:
		l.buffer.WriteRune('$')
		l.backup()
	case c == '(':
		if l.hasNext('(') {
			l.Arith()
		} else {
			l.Subshell()
		}
	case char.IsFirstInVarName(c), char.IsDigit(c), char.IsSpecial(c):
		l.backup()
		l.VariableSimple()
	case c == '{':
		l.VariableComplex()
	}
}
コード例 #3
0
ファイル: lexer.go プロジェクト: danwakefield/gosh
func (l *Lexer) VariableComplex() {
	// Upon entering we have read the opening '{'
	l.buffer.WriteRune(SentinalSubstitution)
	sv := SubVariable{}
	varbuf := bytes.Buffer{}

	defer func() {
		// We defer this as there are multiple return points
		sv.VarName = varbuf.String()
		l.subs = append(l.subs, sv)
	}()

	if l.hasNext('#') {
		// The NParam Special Var
		if l.hasNext('}') {
			varbuf.WriteRune('#')
			return
		}

		// Length variable operator
		sv.SubType = VarSubLength
	}

	c := l.nextChar()
	switch {
	case char.IsSpecial(c):
		varbuf.WriteRune(c)
	case char.IsDigit(c):
		for {
			varbuf.WriteRune(c)
			c = l.nextChar()
			if !char.IsDigit(c) {
				l.backup()
				break
			}
		}
	case char.IsFirstInVarName(c):
		for {
			varbuf.WriteRune(c)
			c = l.nextChar()
			if !char.IsInVarName(c) {
				l.backup()
				break
			}
		}
	case c == EOFRune:
		l.backup()
		return
	}

	// Either a Enclosed variable '${foo}' or a length operation '${#foo}'
	if l.hasNext('}') {
		return
	}

	// Length operator should have returned since only ${#varname} is valid
	if sv.SubType == VarSubLength {
		l.log.Error("Line %d: Bad substitution (%s)", l.lineNo, l.input[l.lastPosition:l.position])
		os.Exit(1)
	}

	if l.hasNext(':') {
		sv.CheckNull = true
	}

	switch l.nextChar() {
	case '-':
		sv.SubType = VarSubMinus
	case '+':
		sv.SubType = VarSubPlus
	case '?':
		sv.SubType = VarSubQuestion
	case '=':
		sv.SubType = VarSubAssign
	case '#':
		if l.hasNext('#') {
			sv.SubType = VarSubTrimLeftMax
		} else {
			sv.SubType = VarSubTrimLeft
		}
	case '%':
		if l.hasNext('%') {
			sv.SubType = VarSubTrimRightMax
		} else {
			sv.SubType = VarSubTrimRight
		}
	default:
		l.log.Error("Line %d: Bad substitution (%s)", l.lineNo, l.input[l.lastPosition:l.position])
		os.Exit(1)
	}

	// Read until '}'
	// In the future to support Nested vars etc create new sublexer from
	// l.input[l.pos:] and take the first lexitem as the sub val then adjust
	// this lexer's position and trash sublexer
	c = l.nextChar()
	subValBuf := bytes.Buffer{}
	for {
		if c == '}' {
			break
		}
		subValBuf.WriteRune(c)
		c = l.nextChar()
	}
	sv.SubVal = subValBuf.String()
}