vendor tsgo
This commit is contained in:
156
tools/tsgo/internal/format/rulesmap.go
Normal file
156
tools/tsgo/internal/format/rulesmap.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package format
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/ast"
|
||||
"github.com/microsoft/typescript-go/internal/debug"
|
||||
)
|
||||
|
||||
func getRules(context *FormattingContext, rules []*ruleImpl) []*ruleImpl {
|
||||
bucket := getRulesMap()[getRuleBucketIndex(context.currentTokenSpan.Kind, context.nextTokenSpan.Kind)]
|
||||
if len(bucket) > 0 {
|
||||
ruleActionMask := ruleActionNone
|
||||
outer:
|
||||
for _, rule := range bucket {
|
||||
acceptRuleActions := ^getRuleActionExclusion(ruleActionMask)
|
||||
if rule.Action()&acceptRuleActions != 0 {
|
||||
preds := rule.Context()
|
||||
for _, p := range preds {
|
||||
if !p(context) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
rules = append(rules, rule)
|
||||
ruleActionMask |= rule.Action()
|
||||
}
|
||||
}
|
||||
return rules
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
func getRuleBucketIndex(row ast.Kind, column ast.Kind) int {
|
||||
debug.Assert(row <= ast.KindLastKeyword && column <= ast.KindLastKeyword, "Must compute formatting context from tokens")
|
||||
return (int(row) * mapRowLength) + int(column)
|
||||
}
|
||||
|
||||
const (
|
||||
maskBitSize = 5
|
||||
mask = 0b11111 // MaskBitSize bits
|
||||
mapRowLength = int(ast.KindLastToken) + 1
|
||||
)
|
||||
|
||||
/**
|
||||
* For a given rule action, gets a mask of other rule actions that
|
||||
* cannot be applied at the same position.
|
||||
*/
|
||||
func getRuleActionExclusion(ruleAction ruleAction) ruleAction {
|
||||
mask := ruleActionNone
|
||||
if ruleAction&ruleActionStopProcessingSpaceActions != 0 {
|
||||
mask |= ruleActionModifySpaceAction
|
||||
}
|
||||
if ruleAction&ruleActionStopProcessingTokenActions != 0 {
|
||||
mask |= ruleActionModifyTokenAction
|
||||
}
|
||||
if ruleAction&ruleActionModifySpaceAction != 0 {
|
||||
mask |= ruleActionModifySpaceAction
|
||||
}
|
||||
if ruleAction&ruleActionModifyTokenAction != 0 {
|
||||
mask |= ruleActionModifyTokenAction
|
||||
}
|
||||
return mask
|
||||
}
|
||||
|
||||
var getRulesMap = sync.OnceValue(buildRulesMap)
|
||||
|
||||
func buildRulesMap() [][]*ruleImpl {
|
||||
rules := getAllRules()
|
||||
// Map from bucket index to array of rules
|
||||
m := make([][]*ruleImpl, mapRowLength*mapRowLength)
|
||||
// This array is used only during construction of the rulesbucket in the map
|
||||
rulesBucketConstructionStateList := make([]int, len(m))
|
||||
for _, rule := range rules {
|
||||
specificRule := rule.leftTokenRange.isSpecific && rule.rightTokenRange.isSpecific
|
||||
|
||||
for _, left := range rule.leftTokenRange.tokens {
|
||||
for _, right := range rule.rightTokenRange.tokens {
|
||||
index := getRuleBucketIndex(left, right)
|
||||
m[index] = addRule(m[index], rule.rule, specificRule, rulesBucketConstructionStateList, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type RulesPosition int
|
||||
|
||||
const (
|
||||
RulesPositionStopRulesSpecific RulesPosition = 0
|
||||
RulesPositionStopRulesAny RulesPosition = maskBitSize * 1
|
||||
RulesPositionContextRulesSpecific RulesPosition = maskBitSize * 2
|
||||
RulesPositionContextRulesAny RulesPosition = maskBitSize * 3
|
||||
RulesPositionNoContextRulesSpecific RulesPosition = maskBitSize * 4
|
||||
RulesPositionNoContextRulesAny RulesPosition = maskBitSize * 5
|
||||
)
|
||||
|
||||
// The Rules list contains all the inserted rules into a rulebucket in the following order:
|
||||
//
|
||||
// 1- Ignore rules with specific token combination
|
||||
// 2- Ignore rules with any token combination
|
||||
// 3- Context rules with specific token combination
|
||||
// 4- Context rules with any token combination
|
||||
// 5- Non-context rules with specific token combination
|
||||
// 6- Non-context rules with any token combination
|
||||
//
|
||||
// The member rulesInsertionIndexBitmap is used to describe the number of rules
|
||||
// in each sub-bucket (above) hence can be used to know the index of where to insert
|
||||
// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits.
|
||||
//
|
||||
// Example:
|
||||
// In order to insert a rule to the end of sub-bucket (3), we get the index by adding
|
||||
// the values in the bitmap segments 3rd, 2nd, and 1st.
|
||||
func addRule(rules []*ruleImpl, rule *ruleImpl, specificTokens bool, constructionState []int, rulesBucketIndex int) []*ruleImpl {
|
||||
var position RulesPosition
|
||||
if rule.Action()&ruleActionStopAction != 0 {
|
||||
if specificTokens {
|
||||
position = RulesPositionStopRulesSpecific
|
||||
} else {
|
||||
position = RulesPositionStopRulesAny
|
||||
}
|
||||
} else if len(rule.Context()) != 0 {
|
||||
if specificTokens {
|
||||
position = RulesPositionContextRulesSpecific
|
||||
} else {
|
||||
position = RulesPositionContextRulesAny
|
||||
}
|
||||
} else {
|
||||
if specificTokens {
|
||||
position = RulesPositionNoContextRulesSpecific
|
||||
} else {
|
||||
position = RulesPositionNoContextRulesAny
|
||||
}
|
||||
}
|
||||
|
||||
state := constructionState[rulesBucketIndex]
|
||||
|
||||
rules = slices.Insert(rules, getRuleInsertionIndex(state, position), rule)
|
||||
constructionState[rulesBucketIndex] = increaseInsertionIndex(state, position)
|
||||
return rules
|
||||
}
|
||||
|
||||
func getRuleInsertionIndex(indexBitmap int, maskPosition RulesPosition) int {
|
||||
index := 0
|
||||
for pos := 0; pos <= int(maskPosition); pos += maskBitSize {
|
||||
index += indexBitmap & mask
|
||||
indexBitmap >>= maskBitSize
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func increaseInsertionIndex(indexBitmap int, maskPosition RulesPosition) int {
|
||||
value := ((indexBitmap >> maskPosition) & mask) + 1
|
||||
debug.Assert((value&mask) == value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.")
|
||||
return (indexBitmap & ^(mask << maskPosition)) | (value << maskPosition)
|
||||
}
|
||||
Reference in New Issue
Block a user