fix(tl): support multiple usages of the same flag
This commit is contained in:
parent
e4e51f7d90
commit
62815d26d7
2 changed files with 53 additions and 18 deletions
|
@ -1,6 +1,6 @@
|
||||||
import { calculateStaticSizes } from '../calculator'
|
import { calculateStaticSizes } from '../calculator'
|
||||||
import { computeConstructorIdFromEntry } from '../ctor-id'
|
import { computeConstructorIdFromEntry } from '../ctor-id'
|
||||||
import { TL_PRIMITIVES, TlEntry } from '../types'
|
import { TL_PRIMITIVES, TlArgument, TlEntry } from '../types'
|
||||||
import { snakeToCamel } from './utils'
|
import { snakeToCamel } from './utils'
|
||||||
|
|
||||||
export interface WriterCodegenOptions {
|
export interface WriterCodegenOptions {
|
||||||
|
@ -70,37 +70,58 @@ export function generateWriterCodeForTlEntry(entry: TlEntry, params = DEFAULT_OP
|
||||||
if (!bare) ret += `w.uint(${entry.id});`
|
if (!bare) ret += `w.uint(${entry.id});`
|
||||||
|
|
||||||
const flagsFields: Record<string, 1> = {}
|
const flagsFields: Record<string, 1> = {}
|
||||||
|
const fieldConditions: Record<string, string> = {}
|
||||||
|
|
||||||
entry.arguments.forEach((arg) => {
|
entry.arguments.forEach((arg) => {
|
||||||
if (arg.type === '#') {
|
if (arg.type === '#') {
|
||||||
ret += `var ${arg.name}=${includeFlags ? `v.${arg.name}` : '0'};`
|
ret += `var ${arg.name}=${includeFlags ? `v.${arg.name}` : '0'};`
|
||||||
|
|
||||||
entry.arguments.forEach((arg1) => {
|
const usedByArgs = entry.arguments.filter((a) => a.typeModifiers?.predicate?.startsWith(arg.name + '.'))
|
||||||
const predicate = arg1.typeModifiers?.predicate
|
const indexUsage: Record<string, TlArgument[]> = {}
|
||||||
|
|
||||||
let s
|
usedByArgs.forEach((arg1) => {
|
||||||
|
const index = arg1.typeModifiers!.predicate!.split('.')[1]
|
||||||
|
if (!indexUsage[index]) indexUsage[index] = []
|
||||||
|
indexUsage[index].push(arg1)
|
||||||
|
})
|
||||||
|
|
||||||
if (!predicate || (s = predicate.split('.'))[0] !== arg.name) {
|
Object.entries(indexUsage).forEach(([index, args]) => {
|
||||||
return
|
const bitIndex = parseInt(index)
|
||||||
}
|
|
||||||
|
|
||||||
const arg1Name = snakeToCamel(arg1.name)
|
|
||||||
|
|
||||||
const bitIndex = parseInt(s[1])
|
|
||||||
|
|
||||||
if (isNaN(bitIndex) || bitIndex < 0 || bitIndex > 32) {
|
if (isNaN(bitIndex) || bitIndex < 0 || bitIndex > 32) {
|
||||||
throw new Error(`Invalid predicate: ${predicate} - invalid bit`)
|
throw new Error(`Invalid predicate: ${arg.name}.${bitIndex} - invalid bit`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const conditions: string[] = []
|
||||||
|
args.forEach((arg1) => {
|
||||||
|
const arg1Name = snakeToCamel(arg1.name)
|
||||||
|
|
||||||
|
if (arg1.type === 'true') {
|
||||||
|
conditions.push(`v.${arg1Name}===true`)
|
||||||
|
} else if (arg1.typeModifiers?.isVector || arg1.typeModifiers?.isBareVector) {
|
||||||
|
ret += `var _${arg1Name}=v.${arg1Name}&&v.${arg1Name}.length;`
|
||||||
|
conditions.push(`_${arg1Name}`)
|
||||||
|
} else {
|
||||||
|
ret += `var _${arg1Name}=v.${arg1Name}!==undefined;`
|
||||||
|
conditions.push(`_${arg1Name}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const action = `${arg.name}|=${1 << bitIndex};`
|
const action = `${arg.name}|=${1 << bitIndex};`
|
||||||
|
let condition: string
|
||||||
|
|
||||||
if (arg1.type === 'true') {
|
if (conditions.length > 1) {
|
||||||
ret += `if(v.${arg1Name}===true)${action}`
|
condition = `_${arg.name}_${bitIndex}`
|
||||||
} else if (arg1.typeModifiers?.isVector || arg1.typeModifiers?.isBareVector) {
|
ret += `var ${condition}=${conditions.join('||')};`
|
||||||
ret += `var _${arg1Name}=v.${arg1Name}&&v.${arg1Name}.length;if(_${arg1Name})${action}`
|
|
||||||
} else {
|
} else {
|
||||||
ret += `var _${arg1Name}=v.${arg1Name}!==undefined;if(_${arg1Name})${action}`
|
condition = conditions[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret += `if(${condition})${action}`
|
||||||
|
|
||||||
|
args.forEach((arg) => {
|
||||||
|
fieldConditions[arg.name] = condition
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ret += `w.uint(${arg.name});`
|
ret += `w.uint(${arg.name});`
|
||||||
|
@ -118,7 +139,7 @@ export function generateWriterCodeForTlEntry(entry: TlEntry, params = DEFAULT_OP
|
||||||
if (arg.typeModifiers?.predicate) {
|
if (arg.typeModifiers?.predicate) {
|
||||||
if (type === 'true') return // included in flags
|
if (type === 'true') return // included in flags
|
||||||
|
|
||||||
ret += `if(_${argName})`
|
ret += `if(${fieldConditions[arg.name]})`
|
||||||
} else {
|
} else {
|
||||||
accessor = `h(v,'${argName}')`
|
accessor = `h(v,'${argName}')`
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,20 @@ describe('generateWriterCodeForTlEntry', () => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('generates code for constructors with multiple fields using the same flag', () => {
|
||||||
|
test(
|
||||||
|
'inputMediaPoll#f94e5f1 flags:# solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;',
|
||||||
|
'var flags=0;',
|
||||||
|
'var _solution=v.solution!==undefined;',
|
||||||
|
'var _solutionEntities=v.solutionEntities&&v.solutionEntities.length;',
|
||||||
|
'var _flags_1=_solution||_solutionEntities;',
|
||||||
|
'if(_flags_1)flags|=2;',
|
||||||
|
'w.uint(flags);',
|
||||||
|
'if(_flags_1)w.string(v.solution);',
|
||||||
|
'if(_flags_1)w.vector(w.object,v.solutionEntities);',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('generates code for constructors with vector arguments', () => {
|
it('generates code for constructors with vector arguments', () => {
|
||||||
test(
|
test(
|
||||||
'contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;',
|
'contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;',
|
||||||
|
|
Loading…
Reference in a new issue